From 08ed529cf70f8a42205fa4aa72bccc48ce560a7d Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Thu, 14 Mar 2024 11:59:29 -0700 Subject: [PATCH 1/9] Add tests for POSIX fstat, lseek, and read. b/302715109 Change-Id: I4db736278c54cdf1af85ba03836361f68796aa8f --- starboard/nplb/BUILD.gn | 3 + .../posix_file_get_info_test.cc | 119 ++++++++ .../posix_compliance/posix_file_helpers.h | 101 ------- .../posix_compliance/posix_file_open_test.cc | 2 +- .../posix_compliance/posix_file_read_test.cc | 272 ++++++++++++++++++ .../posix_compliance/posix_file_seek_test.cc | 172 +++++++++++ .../win32/posix_emu/include/sys/socket.h | 9 + .../shared/win32/posix_emu/include/sys/stat.h | 78 ++--- starboard/shared/win32/posix_emu/socket.cc | 39 +++ 9 files changed, 654 insertions(+), 141 deletions(-) create mode 100644 starboard/nplb/posix_compliance/posix_file_get_info_test.cc delete mode 100644 starboard/nplb/posix_compliance/posix_file_helpers.h create mode 100644 starboard/nplb/posix_compliance/posix_file_read_test.cc create mode 100644 starboard/nplb/posix_compliance/posix_file_seek_test.cc diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index 0d61a4bf5129..7eb86fb4a7d1 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn @@ -144,8 +144,11 @@ target(gtest_target_type, "nplb") { "posix_compliance/posix_directory_can_open_test.cc", "posix_compliance/posix_directory_create_test.cc", "posix_compliance/posix_file_close_test.cc", + "posix_compliance/posix_file_get_info_test.cc", "posix_compliance/posix_file_get_path_info_test.cc", "posix_compliance/posix_file_open_test.cc", + "posix_compliance/posix_file_read_test.cc", + "posix_compliance/posix_file_seek_test.cc", "posix_compliance/posix_memory_allocate_aligned_test.cc", "posix_compliance/posix_memory_allocate_test.cc", "posix_compliance/posix_memory_deallocate_aligned_test.cc", diff --git a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc new file mode 100644 index 000000000000..3bc62a3b8f8b --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc @@ -0,0 +1,119 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SB_API_VERSION >= 16 + +#include +#include +#include + +#include +#include + +#include "starboard/common/time.h" +#include "starboard/file.h" +#include "starboard/nplb/file_helpers.h" +#include "starboard/system.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +inline int64_t TimeTToWindowsUsec(time_t time) { + int64_t posix_usec = static_cast(time) * 1000000; + return PosixTimeToWindowsTime(posix_usec); +} + +TEST(PosixFileGetInfoTest, InvalidFileErrors) { + struct stat info; + int result = fstat(-1, &info); + EXPECT_FALSE(result == 0); +} + +TEST(PosixFileGetInfoTest, WorksOnARegularFile) { + // This test is potentially flaky because it's comparing times. So, building + // in extra sensitivity to make flakiness more apparent. + const int kTrials = 100; + for (int i = 0; i < kTrials; ++i) { + // We can't assume filesystem timestamp precision, so go back a minute + // for a better chance to contain the imprecision and rounding errors. + const int64_t kOneMinuteInMicroseconds = 60'000'000; + int64_t time = + PosixTimeToWindowsTime(CurrentPosixTime()) - kOneMinuteInMicroseconds; +#if !SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) +#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) + // On platforms with coarse access time, we assume 1 day precision and go + // back 2 days to avoid rounding issues. + const int64_t kOneDayInMicroseconds = 1'000'000LL * 60LL * 60LL * 24LL; + int64_t coarse_time = PosixTimeToWindowsTime(CurrentPosixTime()) - + (2 * kOneDayInMicroseconds); +#endif // FILESYSTEM_COARSE_ACCESS_TIME +#endif // FILESYSTEM_ZERO_FILEINFO_TIME + + const int kFileSize = 12; + starboard::nplb::ScopedRandomFile random_file(kFileSize); + const std::string& filename = random_file.filename(); + + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)); + + { + struct stat info; + int result = fstat(file, &info); + EXPECT_EQ(kFileSize, info.st_size); + EXPECT_FALSE(S_ISDIR(info.st_mode)); + EXPECT_FALSE(S_ISLNK(info.st_mode)); +#if SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) + EXPECT_LE(0, TimeTToWindowsUsec(info.st_atime)); + EXPECT_LE(0, TimeTToWindowsUsec(info.st_atime)); + EXPECT_LE(0, TimeTToWindowsUsec(info.st_ctime)); +#else + EXPECT_LE(time, TimeTToWindowsUsec(info.st_atime)); +#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) + EXPECT_LE(coarse_time, TimeTToWindowsUsec(info.st_atime)); +#else + EXPECT_LE(time, TimeTToWindowsUsec(info.st_atime)); +#endif // FILESYSTEM_COARSE_ACCESS_TIME + EXPECT_LE(time, TimeTToWindowsUsec(info.st_ctime)); +#endif // FILESYSTEM_ZERO_FILEINFO_TIME + } + + int result = close(file); + EXPECT_TRUE(result == 0); + } +} + +TEST(PosixFileGetInfoTest, WorksOnStaticContentFiles) { + int count = 1; + for (auto filename : GetFileTestsFilePaths()) { + int file = open(filename.c_str(), O_RDONLY); + ASSERT_TRUE(file >= 0); + + struct stat info; + EXPECT_TRUE(fstat(file, &info) == 0); + size_t content_length = GetTestFileExpectedContent(filename).length(); + EXPECT_EQ(content_length, info.st_size); + EXPECT_FALSE(S_ISDIR(info.st_mode)); + EXPECT_FALSE(S_ISLNK(info.st_mode)); + + EXPECT_TRUE(close(file) == 0); + } +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_helpers.h b/starboard/nplb/posix_compliance/posix_file_helpers.h deleted file mode 100644 index 758594f3bc6d..000000000000 --- a/starboard/nplb/posix_compliance/posix_file_helpers.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2024 The Cobalt Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef STARBOARD_NPLB_POSIX_COMPLIANCE_POSIX_FILE_HELPERS_H_ -#define STARBOARD_NPLB_POSIX_COMPLIANCE_POSIX_FILE_HELPERS_H_ - -#include -#include - -#include "starboard/file.h" - -namespace starboard { -namespace nplb { - -// Gets the temporary directory in which ScopedRandomFile places its files. -std::string GetTempDir(); - -// Creates a random file of the given length, and deletes it when the instance -// falls out of scope. -class ScopedRandomFile { - public: - enum { - kDefaultLength = 64, - }; - - enum Create { - kCreate, - kDontCreate, - }; - - // Will create a file of |kDefaultLength| bytes long. - ScopedRandomFile() : size_(kDefaultLength) { - filename_ = MakeRandomFile(size_); - } - - // Will create a file |length| bytes long. - explicit ScopedRandomFile(int length) : size_(length) { - filename_ = MakeRandomFile(size_); - } - - // Will either create a file |length| bytes long, or will just generate a - // filename. |create| is whether to create the file or not. - ScopedRandomFile(int length, Create create) : size_(length) { - filename_ = - (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath()); - } - - // Will either create a file of |kDefaultLength| bytes long, or will just - // generate a filename. |create| is whether to create the file or not. - explicit ScopedRandomFile(Create create) : size_(kDefaultLength) { - filename_ = - (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath()); - } - - ~ScopedRandomFile() { SbFileDelete(filename_.c_str()); } - - // Creates and returns a random filename (no path), but does not create the - // file. - static std::string MakeRandomFilename(); - - // Returns the filename generated for this file. - const std::string& filename() const { return filename_; } - - // Returns the SPECIFIED size of the file (not the size returned by the - // filesystem). - const int size() const { return size_; } - - // Checks |buffer| of size |size| against this class's write pattern, offset - // by |pattern_offset|. Failures print the original line number |line|. - static void ExpectPattern(int pattern_offset, - void* buffer, - int size, - int line); - - private: - // Creates a file with a random name and |length| bytes, returning the path to - // the new file. - static std::string MakeRandomFile(int length); - - // Creates and returns a path to a random file, but does not create the file. - static std::string MakeRandomFilePath(); - - std::string filename_; - int size_; -}; - -} // namespace nplb -} // namespace starboard - -#endif // STARBOARD_NPLB_POSIX_COMPLIANCE_POSIX_FILE_HELPERS_H_ diff --git a/starboard/nplb/posix_compliance/posix_file_open_test.cc b/starboard/nplb/posix_compliance/posix_file_open_test.cc index 6656145e0537..97199acd7fa1 100644 --- a/starboard/nplb/posix_compliance/posix_file_open_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_open_test.cc @@ -19,7 +19,7 @@ #include #include "starboard/file.h" -#include "starboard/nplb/posix_compliance/posix_file_helpers.h" +#include "starboard/nplb/file_helpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace starboard { diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc new file mode 100644 index 000000000000..20c38df00aef --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -0,0 +1,272 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SB_API_VERSION >= 16 + +// close is partially tested in posix_file_open_test.cc. + +#include +#include +#include + +#include "starboard/nplb/file_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +// Sets up an empty test fixture, required for typed tests. +template +class PosixFileReadTest : public testing::Test {}; + +class PosixRead { + public: + static int Read(int file, void* buf, size_t nbyte) { + return read(file, buf, nbyte); + } +}; + +// class PosixReadAll { +// public: +// static int Read(int file, char* data, int size) { +// return SbFileReadAll(file, data, size); +// } +// }; + +typedef testing::Types PosixFileReadTestTypes; + +template +size_t array_size(const T (&)[n]) { + return n; +} + +TYPED_TEST_CASE(PosixFileReadTest, PosixFileReadTestTypes); + +const int kBufferLength = 16 * 1024; + +TYPED_TEST(PosixFileReadTest, InvalidFileErrors) { + char buffer[kBufferLength]; + int result = TypeParam::Read(-1, buffer, kBufferLength); + EXPECT_EQ(-1, result); +} + +TYPED_TEST(PosixFileReadTest, BasicReading) { + // Create a pattern file that is not an even multiple of the buffer size, + // but is over several times the size of the buffer. + const int kFileSize = kBufferLength * 16 / 3; + ScopedRandomFile random_file(kFileSize); + const std::string& filename = random_file.filename(); + + int file = open(filename.c_str(), O_RDONLY | O_BINARY); + ASSERT_TRUE(file >= 0); + + // Create a bigger buffer than necessary, so we can test the memory around + // the portion given to SbFileRead. + const int kRealBufferLength = kBufferLength * 2; + char real_buffer[kRealBufferLength] = {0}; + const int kBufferOffset = kBufferLength / 2; + char* buffer = real_buffer + kBufferOffset; + + // Initialize to some arbitrary pattern so we can verify it later. + for (int i = 0; i < kRealBufferLength; ++i) { + real_buffer[i] = '\xCD'; + } + + // Read and check the whole file. + int total = 0; + int previous_total = 0; + int max = 0; + while (true) { + int bytes_read = TypeParam::Read(file, buffer, kBufferLength); + if (bytes_read == 0) { + break; + } + + // Check that we didn't read more than the buffer size. + EXPECT_GE(kBufferLength, bytes_read); + + // Check that we didn't get an error. + EXPECT_LT(0, bytes_read); + + // Do some accounting to check later. + previous_total = total; + total += bytes_read; + if (bytes_read > max) { + max = bytes_read; + } + + ScopedRandomFile::ExpectPattern(previous_total, buffer, bytes_read, + __LINE__); + } + + // Check that we read the whole file. + EXPECT_EQ(kFileSize, total); + + // check that we didn't write over any other parts of the buffer. + for (int i = 0; i < kBufferOffset; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + } + + for (int i = kBufferOffset + max; i < kRealBufferLength; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + } + + bool result = close(file); + EXPECT_TRUE(result == 0); +} + +TYPED_TEST(PosixFileReadTest, ReadZeroBytes) { + const int kFileSize = kBufferLength; + ScopedRandomFile random_file(kFileSize); + const std::string& filename = random_file.filename(); + + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)); + + // Create a bigger buffer than necessary, so we can test the memory around + // the portion given to SbFileRead. + const int kRealBufferLength = kBufferLength * 2; + char real_buffer[kRealBufferLength] = {0}; + const int kBufferOffset = kBufferLength / 2; + char* buffer = real_buffer + kBufferOffset; + + // Initialize to some arbitrary pattern so we can verify it later. + for (int i = 0; i < kRealBufferLength; ++i) { + real_buffer[i] = '\xCD'; + } + + // Read zero bytes. + for (int i = 0; i < 10; ++i) { + int bytes_read = TypeParam::Read(file, buffer, 0); + EXPECT_EQ(0, bytes_read); + } + + for (int i = 0; i < kRealBufferLength; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + } + + int result = close(file); + EXPECT_TRUE(result == 0); +} + +TYPED_TEST(PosixFileReadTest, ReadFromMiddle) { + const int kFileSize = kBufferLength * 2; + ScopedRandomFile random_file(kFileSize); + const std::string& filename = random_file.filename(); + + int file = open(filename.c_str(), O_RDONLY | O_BINARY); + // ASSERT_TRUE(SbFileIsValid(file)); + + // Create a bigger buffer than necessary, so we can test the memory around + // the portion given to SbFileRead. + const int kRealBufferLength = kBufferLength * 2; + char real_buffer[kRealBufferLength] = {0}; + const int kBufferOffset = kBufferLength / 2; + char* buffer = real_buffer + kBufferOffset; + + // Initialize to some arbitrary pattern so we can verify it later. + for (int i = 0; i < kRealBufferLength; ++i) { + real_buffer[i] = '\xCD'; + } + + // Read from the middle of the file. + int position = static_cast(lseek(file, kFileSize / 4, SEEK_SET)); + EXPECT_EQ(kFileSize / 4, position); + int bytes_read = TypeParam::Read(file, buffer, kBufferLength); + EXPECT_GE(kBufferLength, bytes_read); + EXPECT_LT(0, bytes_read); + + ScopedRandomFile::ExpectPattern(position, buffer, bytes_read, __LINE__); + + for (int i = 0; i < kBufferOffset; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + if ('\xCD' != real_buffer[i]) + break; + } + + for (int i = kBufferOffset + bytes_read; i < kRealBufferLength; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + if ('\xCD' != real_buffer[i]) + break; + } + + int result = close(file); + EXPECT_TRUE(result == 0); +} + +TYPED_TEST(PosixFileReadTest, ReadStaticContent) { + for (auto filename : GetFileTestsFilePaths()) { + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)) << "Can't open: " << filename; + + // Create a bigger buffer than necessary, so we can test the memory around + // the portion given to SbFileRead. + const int kRealBufferLength = kBufferLength * 2; + char real_buffer[kRealBufferLength] = {0}; + const int kBufferOffset = kBufferLength / 2; + char* buffer = real_buffer + kBufferOffset; + + // Initialize to some arbitrary pattern so we can verify it later. + for (int i = 0; i < kRealBufferLength; ++i) { + real_buffer[i] = '\xCD'; + } + + // Read and check the whole file. + std::string content; + int total = 0; + int max = 0; + while (true) { + int bytes_read = TypeParam::Read(file, buffer, kBufferLength); + if (bytes_read == 0) { + break; + } + + // Check that we didn't read more than the buffer size. + EXPECT_GE(kBufferLength, bytes_read); + + // Check that we didn't get an error. + EXPECT_LT(0, bytes_read); + + // Do some accounting to check later. + total += bytes_read; + if (bytes_read > max) { + max = bytes_read; + } + + // Accumulate the content of the whole file. + content.append(buffer, bytes_read); + } + + // Check that we didn't write over any other parts of the buffer. + for (int i = 0; i < kBufferOffset; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + } + + for (int i = kBufferOffset + max; i < kRealBufferLength; ++i) { + EXPECT_EQ('\xCD', real_buffer[i]); + } + + EXPECT_EQ(GetTestFileExpectedContent(filename), content); + + int result = close(file); + EXPECT_TRUE(result == 0); + } +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_seek_test.cc b/starboard/nplb/posix_compliance/posix_file_seek_test.cc new file mode 100644 index 000000000000..1bf41c93236a --- /dev/null +++ b/starboard/nplb/posix_compliance/posix_file_seek_test.cc @@ -0,0 +1,172 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SB_API_VERSION >= 16 + +#include +#include +#include + +#include +#include + +#include "starboard/file.h" +#include "starboard/nplb/file_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +TEST(PosixFileSeekTest, InvalidFileErrors) { + int invalid_fd = -1; + int result = static_cast(lseek(invalid_fd, 50, SEEK_SET)); + EXPECT_EQ(-1, result); + + result = static_cast(lseek(invalid_fd, -50, SEEK_END)); + EXPECT_EQ(-1, result); + + result = static_cast(lseek(invalid_fd, -50, SEEK_CUR)); + EXPECT_EQ(-1, result); + + result = static_cast(lseek(invalid_fd, 50, SEEK_CUR)); + EXPECT_EQ(-1, result); +} + +TEST(PosixFileSeekTest, FromEndWorks) { + starboard::nplb::ScopedRandomFile random_file; + const std::string& filename = random_file.filename(); + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(fcntl(fd, F_GETFD) != -1 || errno != EBADF); + + struct stat info; + int result = fstat(file, &info); + EXPECT_TRUE(result == 0); + + int64_t position = lseek(file, 0, SEEK_END); + EXPECT_EQ(info.st_size, position); + + int64_t target = -(random_file.size() / 6); + position = lseek(file, target, SEEK_END); + EXPECT_EQ(info.st_size + target, position); + + position = lseek(file, -info.st_size, SEEK_END); + EXPECT_EQ(0, position); + + result = close(file); + EXPECT_TRUE(result == 0); +} + +TEST(PosixFileSeekTest, FromCurrentWorks) { + starboard::nplb::ScopedRandomFile random_file; + const std::string& filename = random_file.filename(); + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)); + + struct stat info; + int result = fstat(file, &info); + EXPECT_TRUE(result == 0); + + int64_t position = lseek(file, 0, SEEK_CUR); + EXPECT_EQ(0, position); + + int64_t target = random_file.size() / 6; + position = lseek(file, target, SEEK_CUR); + EXPECT_EQ(target, position); + + position = lseek(file, target, SEEK_CUR); + EXPECT_EQ(target * 2, position); + + position = lseek(file, 0, SEEK_CUR); + EXPECT_EQ(target * 2, position); + + position = lseek(file, info.st_size - position, SEEK_CUR); + EXPECT_EQ(info.st_size, position); + + position = lseek(file, -info.st_size, SEEK_CUR); + EXPECT_EQ(0, position); + + result = close(file); + EXPECT_TRUE(result == 0); +} + +TEST(PosixFileSeekTest, FromBeginWorks) { + starboard::nplb::ScopedRandomFile random_file; + const std::string& filename = random_file.filename(); + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)); + + struct stat info; + int result = fstat(file, &info); + EXPECT_TRUE(result == 0); + + int64_t position = lseek(file, 0, SEEK_SET); + EXPECT_EQ(0, position); + + int64_t target = random_file.size() / 6; + position = lseek(file, target, SEEK_SET); + EXPECT_EQ(target, position); + + target = random_file.size() / 3; + position = lseek(file, target, SEEK_SET); + EXPECT_EQ(target, position); + + target = info.st_size - random_file.size() / 6; + position = lseek(file, target, SEEK_SET); + EXPECT_EQ(target, position); + + position = lseek(file, info.st_size, SEEK_SET); + EXPECT_EQ(info.st_size, position); + + result = close(file); + EXPECT_TRUE(result == 0); +} + +std::string GetTestStaticContentFile() { + std::string filename = GetFileTestsFilePaths().front(); + int content_length = GetTestFileExpectedContent(filename).length(); + EXPECT_GT(content_length, 40); + return filename; +} + +TEST(PosixFileSeekTest, FromEndInStaticContentWorks) { + std::string filename = GetTestStaticContentFile(); + int file = open(filename.c_str(), O_RDONLY); + // ASSERT_TRUE(SbFileIsValid(file)); + + int content_length = GetTestFileExpectedContent(filename).length(); + + struct stat info; + int result = fstat(file, &info); + EXPECT_TRUE(result == 0); + + int64_t position = lseek(file, 0, SEEK_END); + EXPECT_EQ(info.st_size, position); + + int64_t target = -(content_length / 6); + position = lseek(file, target, SEEK_END); + EXPECT_EQ(info.st_size + target, position); + + position = lseek(file, -info.st_size, SEEK_END); + EXPECT_EQ(0, position); + + result = close(file); + EXPECT_TRUE(result == 0); +} + +} // namespace +} // namespace nplb +} // namespace starboard + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/win32/posix_emu/include/sys/socket.h b/starboard/shared/win32/posix_emu/include/sys/socket.h index 88d9d5f7ebc5..fe6e18f0227f 100644 --- a/starboard/shared/win32/posix_emu/include/sys/socket.h +++ b/starboard/shared/win32/posix_emu/include/sys/socket.h @@ -25,6 +25,12 @@ extern "C" { #endif +int sb_lseek(int fd, off_t offset, int origin); +#define lseek sb_lseek + +SSIZE_T sb_read(int fildes, void* buf, size_t nbyte); +#define read sb_read + int sb_socket(int domain, int type, int protocol); #define socket sb_socket @@ -69,6 +75,9 @@ int sb_setsockopt(int socket, int option_len); #define setsockopt sb_setsockopt +int sb_fstat(int fd, struct stat* buffer); +#define fstat sb_fstat + #ifdef __cplusplus } #endif diff --git a/starboard/shared/win32/posix_emu/include/sys/stat.h b/starboard/shared/win32/posix_emu/include/sys/stat.h index f02aa0b343b8..9e031c95ba0b 100644 --- a/starboard/shared/win32/posix_emu/include/sys/stat.h +++ b/starboard/shared/win32/posix_emu/include/sys/stat.h @@ -1,39 +1,39 @@ -// Copyright 2024 The Cobalt Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ -#define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ - -#include <../ucrt/sys/stat.h> - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define S_ISLNK(mode) 0 // Windows doesn't support symbolic links -#define S_ISDIR(mode) (((mode) & _S_IFMT) == (_S_IFDIR)) -#define S_ISREG(mode) (((mode) & _S_IFMT) == (_S_IFREG)) - -typedef int mode_t; - -int sb_mkdir(const char* path, mode_t mode); -#undef mkdir -#define mkdir sb_mkdir - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ +#define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ + +#include <../ucrt/sys/stat.h> + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define S_ISLNK(mode) 0 // Windows doesn't support symbolic links +#define S_ISDIR(mode) (((mode) & _S_IFMT) == (_S_IFDIR)) +#define S_ISREG(mode) (((mode) & _S_IFMT) == (_S_IFREG)) + +typedef int mode_t; + +int sb_mkdir(const char* path, mode_t mode); +#undef mkdir +#define mkdir sb_mkdir + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_STAT_H_ diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index 01096f2f745d..d0b9a341a75d 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -17,11 +17,15 @@ #include #include // Needed for file-specific `_close`. #include +#include #include // Our version that declares generic `close`. #include #undef NO_ERROR // http://b/302733082#comment15 #include + +#include #include + #include "starboard/common/log.h" #include "starboard/types.h" @@ -285,6 +289,28 @@ int close(int fd) { return _close(handle.file); } +int sb_lseek(int fd, off_t offset, int origin) { + std::cout << "INTERNAL FD IS: " << fd << std::endl; + FileOrSocket handle = handle_db_get(fd, false); + std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; + if (!handle.is_file) { + return -1; + } + std::cout << "LSEEK ON EXTERNAL FD:" << handle.file << std::endl; + return lseek(handle.file, offset, origin); +} + +SSIZE_T sb_read(int fd, void* buf, size_t nbyte) { + std::cout << "INTERNAL FD IS: " << fd << std::endl; + FileOrSocket handle = handle_db_get(fd, false); + std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; + if (!handle.is_file) { + return -1; + } + std::cout << "READ ON EXTERNAL FD:" << handle.file << std::endl; + return read(handle.file, buf, nbyte); +} + int sb_bind(int socket, const struct sockaddr* address, socklen_t address_len) { SOCKET socket_handle = handle_db_get(socket, false).socket; if (socket_handle == INVALID_SOCKET) { @@ -441,7 +467,20 @@ int sb_fcntl(int fd, int cmd, ... /*arg*/) { int opt = 1; ioctlsocket(socket_handle, FIONBIO, reinterpret_cast(&opt)); } + } else if (cmd == F_GETFL) { } return 0; } + +int sb_fstat(int fd, struct stat* buffer) { + std::cout << "INTERNAL FD IS: " << fd << std::endl; + FileOrSocket handle = handle_db_get(fd, false); + std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; + if (!handle.is_file) { + return -1; + } + std::cout << "FSTAT ON EXTERNAL FD:" << handle.file << std::endl; + return fstat(handle.file, buffer); +} + } // extern "C" From 0dce38ad7e62341746475bfcd7303399bb329585 Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Thu, 14 Mar 2024 15:28:36 -0700 Subject: [PATCH 2/9] Add oldnames.lib and header files. Change-Id: I10178cc183bfd81b0d30c20db9dd2b7cd46698ea --- starboard/nplb/posix_compliance/posix_file_get_info_test.cc | 1 + starboard/nplb/posix_compliance/posix_file_read_test.cc | 6 ++++++ starboard/nplb/posix_compliance/posix_file_seek_test.cc | 2 ++ starboard/xb1/platform_configuration/BUILD.gn | 1 + 4 files changed, 10 insertions(+) diff --git a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc index 3bc62a3b8f8b..38aa09fec87e 100644 --- a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc index 20c38df00aef..4c229c118ace 100644 --- a/starboard/nplb/posix_compliance/posix_file_read_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -18,11 +18,17 @@ #include #include +#include +#include #include #include "starboard/nplb/file_helpers.h" #include "testing/gtest/include/gtest/gtest.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + namespace starboard { namespace nplb { namespace { diff --git a/starboard/nplb/posix_compliance/posix_file_seek_test.cc b/starboard/nplb/posix_compliance/posix_file_seek_test.cc index 1bf41c93236a..d1ef4fbbc441 100644 --- a/starboard/nplb/posix_compliance/posix_file_seek_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_seek_test.cc @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include diff --git a/starboard/xb1/platform_configuration/BUILD.gn b/starboard/xb1/platform_configuration/BUILD.gn index 85a72d667de4..6dfe2337f1ee 100644 --- a/starboard/xb1/platform_configuration/BUILD.gn +++ b/starboard/xb1/platform_configuration/BUILD.gn @@ -72,6 +72,7 @@ config("target") { "iso_stdio_wide_specifiers.lib", "mfplat.lib", "mfuuid.lib", + "oldnames.lib", "windowsapp.lib", ] ldflags += [ From e3754117f561ba1b7515e6cced8f3dbce17af39f Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Thu, 14 Mar 2024 15:58:10 -0700 Subject: [PATCH 3/9] Move O_BINARY to Windows emu layer. Change-Id: Ibf6fd9aa98c492fc51d73a4b69c8d66c4a4f1ae6 --- starboard/elf_loader/exported_symbols.cc | 1 + .../posix_compliance/posix_file_get_info_test.cc | 2 +- .../posix_compliance/posix_file_read_test.cc | 16 +++++----------- .../posix_compliance/posix_file_seek_test.cc | 8 ++++---- starboard/shared/win32/posix_emu/socket.cc | 12 ++---------- 5 files changed, 13 insertions(+), 26 deletions(-) diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index 32d00b3449d5..7c7b1dd37059 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -464,6 +464,7 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(free); REGISTER_SYMBOL(freeaddrinfo); REGISTER_SYMBOL(freeifaddrs); + REGISTER_SYMBOL(fstat); REGISTER_SYMBOL(getaddrinfo); REGISTER_SYMBOL(getifaddrs); REGISTER_SYMBOL(getsockname); diff --git a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc index 38aa09fec87e..7c84ad15ba33 100644 --- a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc @@ -68,7 +68,7 @@ TEST(PosixFileGetInfoTest, WorksOnARegularFile) { const std::string& filename = random_file.filename(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)); + ASSERT_TRUE(file >= 0); { struct stat info; diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc index 4c229c118ace..54415eb960f6 100644 --- a/starboard/nplb/posix_compliance/posix_file_read_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -14,8 +14,6 @@ #if SB_API_VERSION >= 16 -// close is partially tested in posix_file_open_test.cc. - #include #include #include @@ -25,10 +23,6 @@ #include "starboard/nplb/file_helpers.h" #include "testing/gtest/include/gtest/gtest.h" -#ifndef O_BINARY -#define O_BINARY 0 -#endif - namespace starboard { namespace nplb { namespace { @@ -75,7 +69,7 @@ TYPED_TEST(PosixFileReadTest, BasicReading) { ScopedRandomFile random_file(kFileSize); const std::string& filename = random_file.filename(); - int file = open(filename.c_str(), O_RDONLY | O_BINARY); + int file = open(filename.c_str(), O_RDONLY); ASSERT_TRUE(file >= 0); // Create a bigger buffer than necessary, so we can test the memory around @@ -139,7 +133,7 @@ TYPED_TEST(PosixFileReadTest, ReadZeroBytes) { const std::string& filename = random_file.filename(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)); + ASSERT_TRUE(file >= 0); // Create a bigger buffer than necessary, so we can test the memory around // the portion given to SbFileRead. @@ -172,8 +166,8 @@ TYPED_TEST(PosixFileReadTest, ReadFromMiddle) { ScopedRandomFile random_file(kFileSize); const std::string& filename = random_file.filename(); - int file = open(filename.c_str(), O_RDONLY | O_BINARY); - // ASSERT_TRUE(SbFileIsValid(file)); + int file = open(filename.c_str(), O_RDONLY); + ASSERT_TRUE(file >= 0); // Create a bigger buffer than necessary, so we can test the memory around // the portion given to SbFileRead. @@ -215,7 +209,7 @@ TYPED_TEST(PosixFileReadTest, ReadFromMiddle) { TYPED_TEST(PosixFileReadTest, ReadStaticContent) { for (auto filename : GetFileTestsFilePaths()) { int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)) << "Can't open: " << filename; + ASSERT_TRUE(file >= 0) << "Can't open: " << filename; // Create a bigger buffer than necessary, so we can test the memory around // the portion given to SbFileRead. diff --git a/starboard/nplb/posix_compliance/posix_file_seek_test.cc b/starboard/nplb/posix_compliance/posix_file_seek_test.cc index d1ef4fbbc441..45d0da1d0078 100644 --- a/starboard/nplb/posix_compliance/posix_file_seek_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_seek_test.cc @@ -50,7 +50,7 @@ TEST(PosixFileSeekTest, FromEndWorks) { starboard::nplb::ScopedRandomFile random_file; const std::string& filename = random_file.filename(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(fcntl(fd, F_GETFD) != -1 || errno != EBADF); + ASSERT_TRUE(file >= 0); struct stat info; int result = fstat(file, &info); @@ -74,7 +74,7 @@ TEST(PosixFileSeekTest, FromCurrentWorks) { starboard::nplb::ScopedRandomFile random_file; const std::string& filename = random_file.filename(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)); + ASSERT_TRUE(file >= 0); struct stat info; int result = fstat(file, &info); @@ -107,7 +107,7 @@ TEST(PosixFileSeekTest, FromBeginWorks) { starboard::nplb::ScopedRandomFile random_file; const std::string& filename = random_file.filename(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)); + ASSERT_TRUE(file >= 0); struct stat info; int result = fstat(file, &info); @@ -145,7 +145,7 @@ std::string GetTestStaticContentFile() { TEST(PosixFileSeekTest, FromEndInStaticContentWorks) { std::string filename = GetTestStaticContentFile(); int file = open(filename.c_str(), O_RDONLY); - // ASSERT_TRUE(SbFileIsValid(file)); + ASSERT_TRUE(file >= 0); int content_length = GetTestFileExpectedContent(filename).length(); diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index d0b9a341a75d..c1f256e2f5f2 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -23,7 +23,6 @@ #undef NO_ERROR // http://b/302733082#comment15 #include -#include #include #include "starboard/common/log.h" @@ -256,6 +255,8 @@ int open(const char* path, int oflag, ...) { va_start(args, oflag); int fd; mode_t mode; + // Open in binary mode because read() stops at the first 0x1A value. + oflag |= O_BINARY; if (oflag & O_CREAT) { mode = va_arg(args, mode_t); fd = _open(path, oflag, mode & MS_MODE_MASK); @@ -290,24 +291,18 @@ int close(int fd) { } int sb_lseek(int fd, off_t offset, int origin) { - std::cout << "INTERNAL FD IS: " << fd << std::endl; FileOrSocket handle = handle_db_get(fd, false); - std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; if (!handle.is_file) { return -1; } - std::cout << "LSEEK ON EXTERNAL FD:" << handle.file << std::endl; return lseek(handle.file, offset, origin); } SSIZE_T sb_read(int fd, void* buf, size_t nbyte) { - std::cout << "INTERNAL FD IS: " << fd << std::endl; FileOrSocket handle = handle_db_get(fd, false); - std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; if (!handle.is_file) { return -1; } - std::cout << "READ ON EXTERNAL FD:" << handle.file << std::endl; return read(handle.file, buf, nbyte); } @@ -473,13 +468,10 @@ int sb_fcntl(int fd, int cmd, ... /*arg*/) { } int sb_fstat(int fd, struct stat* buffer) { - std::cout << "INTERNAL FD IS: " << fd << std::endl; FileOrSocket handle = handle_db_get(fd, false); - std::cout << "HANDLE HAS VALUE OF " << handle.file << std::endl; if (!handle.is_file) { return -1; } - std::cout << "FSTAT ON EXTERNAL FD:" << handle.file << std::endl; return fstat(handle.file, buffer); } From d05c563207dbd37fbc76d29bb46f6a64f5e5d567 Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Wed, 20 Mar 2024 19:39:01 -0700 Subject: [PATCH 4/9] Add read, lseek to exported symbols. Change-Id: I543758f16bfc2540592792cb10e25bed1283b6b2 --- starboard/elf_loader/exported_symbols.cc | 2 ++ starboard/shared/win32/posix_emu/include/sys/socket.h | 1 + starboard/shared/win32/posix_emu/socket.cc | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index 7c7b1dd37059..587dce3caec0 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -469,6 +469,7 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(getifaddrs); REGISTER_SYMBOL(getsockname); REGISTER_SYMBOL(listen); + REGISTER_SYMBOL(lseek); REGISTER_SYMBOL(malloc); REGISTER_SYMBOL(mkdir); REGISTER_SYMBOL(mprotect); @@ -476,6 +477,7 @@ ExportedSymbols::ExportedSymbols() { REGISTER_SYMBOL(munmap); REGISTER_SYMBOL(open); REGISTER_SYMBOL(posix_memalign); + REGISTER_SYMBOL(read); REGISTER_SYMBOL(realloc); REGISTER_SYMBOL(recv); REGISTER_SYMBOL(send); diff --git a/starboard/shared/win32/posix_emu/include/sys/socket.h b/starboard/shared/win32/posix_emu/include/sys/socket.h index fe6e18f0227f..21fe66878361 100644 --- a/starboard/shared/win32/posix_emu/include/sys/socket.h +++ b/starboard/shared/win32/posix_emu/include/sys/socket.h @@ -16,6 +16,7 @@ #define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_SOCKET_H_ #include +#include #include #include diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index c1f256e2f5f2..60ba27fe22c8 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -462,7 +462,6 @@ int sb_fcntl(int fd, int cmd, ... /*arg*/) { int opt = 1; ioctlsocket(socket_handle, FIONBIO, reinterpret_cast(&opt)); } - } else if (cmd == F_GETFL) { } return 0; } From b6b9d30e62ef13eba1797ad875fefb58f62d89ed Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Wed, 3 Apr 2024 18:02:15 -0700 Subject: [PATCH 5/9] Implement ReadAll. Change-Id: I7b70a6afc0769320e8bd6f06133819b57cbc6163 --- starboard/common/file.cc | 23 +++++++++++++++++++ starboard/common/file.h | 4 ++++ .../posix_file_get_info_test.cc | 19 --------------- .../posix_file_get_path_info_test.cc | 18 --------------- .../posix_compliance/posix_file_read_test.cc | 15 ++++++------ .../win32/posix_emu/include/sys/socket.h | 12 +++++----- third_party/musl/include/sys/stat.h | 2 +- 7 files changed, 42 insertions(+), 51 deletions(-) diff --git a/starboard/common/file.cc b/starboard/common/file.cc index 3dc007e761e2..b2be9a18c50e 100644 --- a/starboard/common/file.cc +++ b/starboard/common/file.cc @@ -14,7 +14,13 @@ #include "starboard/common/file.h" +#ifdef _WIN32 +#include +#else +#include +#endif #include +#include #include #include @@ -40,6 +46,23 @@ bool DirectoryCloseLogFailure(const char* path, SbDirectory dir) { } // namespace +ssize_t ReadAll(int fd, char* data, int size) { + if (fd < 0 || size < 0) { + return -1; + } + ssize_t bytes_read = 0; + ssize_t rv; + do { + rv = read(fd, data + bytes_read, size - bytes_read); + if (rv <= 0) { + break; + } + bytes_read += rv; + } while (bytes_read < size); + + return bytes_read ? bytes_read : rv; +} + void RecordFileWriteStat(int write_file_result) { auto& stats_tracker = StatsTrackerContainer::GetInstance()->stats_tracker(); if (write_file_result <= 0) { diff --git a/starboard/common/file.h b/starboard/common/file.h index 3965042eb768..58e2e0221c4f 100644 --- a/starboard/common/file.h +++ b/starboard/common/file.h @@ -22,8 +22,12 @@ #include "starboard/file.h" +#include + namespace starboard { +ssize_t ReadAll(int fd, char* data, int size); + void RecordFileWriteStat(int write_file_result); // Deletes the file, symlink or directory at |path|. When |path| is a directory, diff --git a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc index 7c84ad15ba33..c495508ab091 100644 --- a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc @@ -53,15 +53,6 @@ TEST(PosixFileGetInfoTest, WorksOnARegularFile) { const int64_t kOneMinuteInMicroseconds = 60'000'000; int64_t time = PosixTimeToWindowsTime(CurrentPosixTime()) - kOneMinuteInMicroseconds; -#if !SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) -#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) - // On platforms with coarse access time, we assume 1 day precision and go - // back 2 days to avoid rounding issues. - const int64_t kOneDayInMicroseconds = 1'000'000LL * 60LL * 60LL * 24LL; - int64_t coarse_time = PosixTimeToWindowsTime(CurrentPosixTime()) - - (2 * kOneDayInMicroseconds); -#endif // FILESYSTEM_COARSE_ACCESS_TIME -#endif // FILESYSTEM_ZERO_FILEINFO_TIME const int kFileSize = 12; starboard::nplb::ScopedRandomFile random_file(kFileSize); @@ -76,19 +67,9 @@ TEST(PosixFileGetInfoTest, WorksOnARegularFile) { EXPECT_EQ(kFileSize, info.st_size); EXPECT_FALSE(S_ISDIR(info.st_mode)); EXPECT_FALSE(S_ISLNK(info.st_mode)); -#if SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) - EXPECT_LE(0, TimeTToWindowsUsec(info.st_atime)); - EXPECT_LE(0, TimeTToWindowsUsec(info.st_atime)); - EXPECT_LE(0, TimeTToWindowsUsec(info.st_ctime)); -#else EXPECT_LE(time, TimeTToWindowsUsec(info.st_atime)); -#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) - EXPECT_LE(coarse_time, TimeTToWindowsUsec(info.st_atime)); -#else EXPECT_LE(time, TimeTToWindowsUsec(info.st_atime)); -#endif // FILESYSTEM_COARSE_ACCESS_TIME EXPECT_LE(time, TimeTToWindowsUsec(info.st_ctime)); -#endif // FILESYSTEM_ZERO_FILEINFO_TIME } int result = close(file); diff --git a/starboard/nplb/posix_compliance/posix_file_get_path_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_path_info_test.cc index 2a5a857cc5b6..fbada38a57dc 100644 --- a/starboard/nplb/posix_compliance/posix_file_get_path_info_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_get_path_info_test.cc @@ -51,13 +51,6 @@ TEST(PosixFileGetPathInfoTest, WorksOnARegularFile) { // for a better chance to contain the imprecision and rounding errors. const int64_t kOneSecondInMicroseconds = 1'000'000; int64_t time = PosixTimeToWindowsTime(CurrentPosixTime()); -#if !SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) -#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) - // On platforms with coarse access time, we assume 1 day precision and go - // back 2 days to avoid rounding issues. - const int64_t kOneDayInMicroseconds = 1'000'000LL * 60LL * 60LL * 24LL; -#endif // FILESYSTEM_COARSE_ACCESS_TIME -#endif // FILESYSTEM_ZERO_FILEINFO_TIME const int kFileSize = 12; ScopedRandomFile random_file(kFileSize); @@ -69,23 +62,12 @@ TEST(PosixFileGetPathInfoTest, WorksOnARegularFile) { EXPECT_EQ(kFileSize, file_info.st_size); EXPECT_FALSE(S_ISDIR(file_info.st_mode)); EXPECT_FALSE(S_ISLNK(file_info.st_mode)); -#if SB_HAS_QUIRK(FILESYSTEM_ZERO_FILEINFO_TIME) - EXPECT_LE(0, TimeTToWindowsUsecTest(file_info.at_ctime)); - EXPECT_LE(0, TimeTToWindowsUsecTest(file_info.mt_ctime)); - EXPECT_LE(0, TimeTToWindowsUsecTest(file_info.st_ctime)); -#else EXPECT_NEAR(time, TimeTToWindowsUsecTest(file_info.st_mtime), kOneSecondInMicroseconds); -#if SB_HAS_QUIRK(FILESYSTEM_COARSE_ACCESS_TIME) - EXPECT_NEAR(time, TimeTToWindowsUsecTest(file_info.at_ctime), - 2 * kOneDayInMicroseconds); -#else EXPECT_NEAR(time, TimeTToWindowsUsecTest(file_info.st_atime), kOneSecondInMicroseconds); -#endif // FILESYSTEM_COARSE_ACCESS_TIME EXPECT_NEAR(time, TimeTToWindowsUsecTest(file_info.st_ctime), kOneSecondInMicroseconds); -#endif // FILESYSTEM_ZERO_FILEINFO_TIME } } } diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc index 54415eb960f6..4d76a17dff03 100644 --- a/starboard/nplb/posix_compliance/posix_file_read_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -20,6 +20,7 @@ #include #include +#include "starboard/common/file.h" #include "starboard/nplb/file_helpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,14 +39,14 @@ class PosixRead { } }; -// class PosixReadAll { -// public: -// static int Read(int file, char* data, int size) { -// return SbFileReadAll(file, data, size); -// } -// }; +class PosixReadAll { + public: + static int Read(int file, char* data, int size) { + return ReadAll(file, data, size); + } +}; -typedef testing::Types PosixFileReadTestTypes; +typedef testing::Types PosixFileReadTestTypes; template size_t array_size(const T (&)[n]) { diff --git a/starboard/shared/win32/posix_emu/include/sys/socket.h b/starboard/shared/win32/posix_emu/include/sys/socket.h index 21fe66878361..2344b7606cc3 100644 --- a/starboard/shared/win32/posix_emu/include/sys/socket.h +++ b/starboard/shared/win32/posix_emu/include/sys/socket.h @@ -26,12 +26,6 @@ extern "C" { #endif -int sb_lseek(int fd, off_t offset, int origin); -#define lseek sb_lseek - -SSIZE_T sb_read(int fildes, void* buf, size_t nbyte); -#define read sb_read - int sb_socket(int domain, int type, int protocol); #define socket sb_socket @@ -79,6 +73,12 @@ int sb_setsockopt(int socket, int sb_fstat(int fd, struct stat* buffer); #define fstat sb_fstat +int sb_lseek(int fd, off_t offset, int origin); +#define lseek sb_lseek + +SSIZE_T sb_read(int fildes, void* buf, size_t nbyte); +#define read sb_read + #ifdef __cplusplus } #endif diff --git a/third_party/musl/include/sys/stat.h b/third_party/musl/include/sys/stat.h index 9f5abb81c935..3d6bff532b92 100644 --- a/third_party/musl/include/sys/stat.h +++ b/third_party/musl/include/sys/stat.h @@ -113,8 +113,8 @@ int lchmod(const char *, mode_t); #if _REDIR_TIME64 #if !defined(STARBOARD) __REDIR(stat, __stat_time64); -#endif // !defined(STARBOARD) __REDIR(fstat, __fstat_time64); +#endif // !defined(STARBOARD) __REDIR(lstat, __lstat_time64); __REDIR(fstatat, __fstatat_time64); __REDIR(futimens, __futimens_time64); From 68ccc8b098f66f4eddb46f218155b4c8f346b9b1 Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Wed, 10 Apr 2024 00:28:56 -0700 Subject: [PATCH 6/9] Add ABI wrapper for fstat. Change-Id: I4c8469b8655d3618e3221f7a50dea1bcb14ea5f4 --- starboard/elf_loader/exported_symbols.cc | 1 + .../cobalt_layer_posix_stat_abi_wrappers.cc | 5 +++ ...starboard_layer_posix_stat_abi_wrappers.cc | 42 ++++++++++++------- .../starboard_layer_posix_stat_abi_wrappers.h | 1 + 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index 587dce3caec0..c67b0481a9a8 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -501,6 +501,7 @@ ExportedSymbols::ExportedSymbols() { // TODO: b/316603042 - Detect via NPLB and only add the wrapper if needed. map_["clock_gettime"] = reinterpret_cast(&__abi_wrap_clock_gettime); + map_["fstat"] = reinterpret_cast(&__abi_wrap_fstat); map_["gettimeofday"] = reinterpret_cast(&__abi_wrap_gettimeofday); map_["gmtime_r"] = reinterpret_cast(&__abi_wrap_gmtime_r); diff --git a/starboard/shared/modular/cobalt_layer_posix_stat_abi_wrappers.cc b/starboard/shared/modular/cobalt_layer_posix_stat_abi_wrappers.cc index c37d48557a97..64be3a1c4b0e 100644 --- a/starboard/shared/modular/cobalt_layer_posix_stat_abi_wrappers.cc +++ b/starboard/shared/modular/cobalt_layer_posix_stat_abi_wrappers.cc @@ -18,8 +18,13 @@ extern "C" { +int __abi_wrap_fstat(int fildes, struct stat* info); int __abi_wrap_stat(const char* path, struct stat* info); +int fstat(int fildes, struct stat* info) { + return __abi_wrap_fstat(fildes, info); +} + int stat(const char* path, struct stat* info) { return __abi_wrap_stat(path, info); } diff --git a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.cc b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.cc index e11f3f0084d9..4f1602662904 100644 --- a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.cc +++ b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.cc @@ -14,31 +14,41 @@ #include "starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h" -int __abi_wrap_stat(const char* path, struct musl_stat* musl_info) { - struct stat stat_info; // The type from platform toolchain. - int retval = stat(path, &stat_info); - +int stat_helper(int retval, + struct stat* stat_info, + struct musl_stat* musl_info) { if (retval != 0 || musl_info == NULL) { return -1; } - musl_info->st_size = stat_info.st_size; - musl_info->st_mode = stat_info.st_mode; + musl_info->st_size = stat_info->st_size; + musl_info->st_mode = stat_info->st_mode; #if defined(_MSC_VER) - musl_info->st_atim.tv_sec = stat_info.st_atime; + musl_info->st_atim.tv_sec = stat_info->st_atime; musl_info->st_atim.tv_nsec = 0; - musl_info->st_mtim.tv_sec = stat_info.st_mtime; + musl_info->st_mtim.tv_sec = stat_info->st_mtime; musl_info->st_mtim.tv_nsec = 0; - musl_info->st_ctim.tv_sec = stat_info.st_ctime; + musl_info->st_ctim.tv_sec = stat_info->st_ctime; musl_info->st_ctim.tv_nsec = 0; #else - musl_info->st_atim.tv_sec = stat_info.st_atim.tv_sec; - musl_info->st_atim.tv_nsec = stat_info.st_atim.tv_nsec; - musl_info->st_mtim.tv_sec = stat_info.st_mtim.tv_sec; - musl_info->st_mtim.tv_nsec = stat_info.st_mtim.tv_nsec; - musl_info->st_ctim.tv_sec = stat_info.st_ctim.tv_sec; - musl_info->st_ctim.tv_nsec = stat_info.st_ctim.tv_nsec; + musl_info->st_atim.tv_sec = stat_info->st_atim.tv_sec; + musl_info->st_atim.tv_nsec = stat_info->st_atim.tv_nsec; + musl_info->st_mtim.tv_sec = stat_info->st_mtim.tv_sec; + musl_info->st_mtim.tv_nsec = stat_info->st_mtim.tv_nsec; + musl_info->st_ctim.tv_sec = stat_info->st_ctim.tv_sec; + musl_info->st_ctim.tv_nsec = stat_info->st_ctim.tv_nsec; #endif - return retval; } + +int __abi_wrap_fstat(int fildes, struct musl_stat* musl_info) { + struct stat stat_info; // The type from platform toolchain. + int retval = fstat(fildes, &stat_info); + return stat_helper(retval, &stat_info, musl_info); +} + +int __abi_wrap_stat(const char* path, struct musl_stat* musl_info) { + struct stat stat_info; // The type from platform toolchain. + int retval = stat(path, &stat_info); + return stat_helper(retval, &stat_info, musl_info); +} diff --git a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h index 976e1593a9e6..ce08855c5968 100644 --- a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h +++ b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h @@ -75,6 +75,7 @@ struct musl_stat { #endif }; +SB_EXPORT int __abi_wrap_fstat(int fildes, struct musl_stat* info); SB_EXPORT int __abi_wrap_stat(const char* path, struct musl_stat* info); #ifdef __cplusplus From e42c5ffc2ab234c6ec17f5d0846161757d30b5f3 Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Wed, 10 Apr 2024 17:57:08 -0700 Subject: [PATCH 7/9] Add ABI wrapper for lseek and read. Change-Id: I6966eac26431373e6eccd70f9b31386daac5717d --- starboard/common/file.cc | 7 ++- starboard/common/file.h | 2 +- starboard/elf_loader/exported_symbols.cc | 3 + .../posix_compliance/posix_file_read_test.cc | 4 +- starboard/shared/modular/BUILD.gn | 3 + .../cobalt_layer_posix_file_abi_wrappers.cc | 34 ++++++++++ ...starboard_layer_posix_file_abi_wrappers.cc | 26 ++++++++ .../starboard_layer_posix_file_abi_wrappers.h | 62 +++++++++++++++++++ .../api_leak_detector/api_leak_detector.py | 1 + 9 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 starboard/shared/modular/cobalt_layer_posix_file_abi_wrappers.cc create mode 100644 starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc create mode 100644 starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h diff --git a/starboard/common/file.cc b/starboard/common/file.cc index b2be9a18c50e..36e6eec41bce 100644 --- a/starboard/common/file.cc +++ b/starboard/common/file.cc @@ -46,14 +46,17 @@ bool DirectoryCloseLogFailure(const char* path, SbDirectory dir) { } // namespace -ssize_t ReadAll(int fd, char* data, int size) { +ssize_t ReadAll(int fd, void* data, int size) { if (fd < 0 || size < 0) { return -1; } ssize_t bytes_read = 0; ssize_t rv; do { - rv = read(fd, data + bytes_read, size - bytes_read); + // Needs to cast void* to char* as MSVC returns error for pointer + // arithmetic. + rv = + read(fd, reinterpret_cast(data) + bytes_read, size - bytes_read); if (rv <= 0) { break; } diff --git a/starboard/common/file.h b/starboard/common/file.h index 58e2e0221c4f..d9c1bbc0ef73 100644 --- a/starboard/common/file.h +++ b/starboard/common/file.h @@ -26,7 +26,7 @@ namespace starboard { -ssize_t ReadAll(int fd, char* data, int size); +ssize_t ReadAll(int fd, void* data, int size); void RecordFileWriteStat(int write_file_result); diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc index c67b0481a9a8..d891bd20739c 100644 --- a/starboard/elf_loader/exported_symbols.cc +++ b/starboard/elf_loader/exported_symbols.cc @@ -52,6 +52,7 @@ #include "starboard/mutex.h" #include "starboard/player.h" #if SB_API_VERSION >= 16 +#include "starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h" #include "starboard/shared/modular/starboard_layer_posix_mmap_abi_wrappers.h" #include "starboard/shared/modular/starboard_layer_posix_pthread_abi_wrappers.h" #include "starboard/shared/modular/starboard_layer_posix_socket_abi_wrappers.h" @@ -505,6 +506,7 @@ ExportedSymbols::ExportedSymbols() { map_["gettimeofday"] = reinterpret_cast(&__abi_wrap_gettimeofday); map_["gmtime_r"] = reinterpret_cast(&__abi_wrap_gmtime_r); + map_["lseek"] = reinterpret_cast(&__abi_wrap_lseek); map_["mmap"] = reinterpret_cast(&__abi_wrap_mmap); map_["pthread_cond_broadcast"] = reinterpret_cast(&__abi_wrap_pthread_cond_broadcast); @@ -560,6 +562,7 @@ ExportedSymbols::ExportedSymbols() { reinterpret_cast(&__abi_wrap_pthread_setspecific); map_["pthread_setname_np"] = reinterpret_cast(&__abi_wrap_pthread_setname_np); + map_["read"] = reinterpret_cast(&__abi_wrap_read); map_["stat"] = reinterpret_cast(&__abi_wrap_stat); map_["time"] = reinterpret_cast(&__abi_wrap_time); map_["accept"] = reinterpret_cast(&__abi_wrap_accept); diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc index 4d76a17dff03..fee22ca3bc5f 100644 --- a/starboard/nplb/posix_compliance/posix_file_read_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -34,14 +34,14 @@ class PosixFileReadTest : public testing::Test {}; class PosixRead { public: - static int Read(int file, void* buf, size_t nbyte) { + static ssize_t Read(int file, void* buf, size_t nbyte) { return read(file, buf, nbyte); } }; class PosixReadAll { public: - static int Read(int file, char* data, int size) { + static ssize_t Read(int file, void* data, int size) { return ReadAll(file, data, size); } }; diff --git a/starboard/shared/modular/BUILD.gn b/starboard/shared/modular/BUILD.gn index bafb44b827e5..7d76132d5166 100644 --- a/starboard/shared/modular/BUILD.gn +++ b/starboard/shared/modular/BUILD.gn @@ -17,6 +17,8 @@ if (sb_is_modular || sb_is_evergreen_compatible) { source_set("starboard_layer_posix_abi_wrappers") { sources = [ + "starboard_layer_posix_file_abi_wrappers.cc", + "starboard_layer_posix_file_abi_wrappers.h", "starboard_layer_posix_mmap_abi_wrappers.cc", "starboard_layer_posix_mmap_abi_wrappers.h", "starboard_layer_posix_pthread_abi_wrappers.cc", @@ -39,6 +41,7 @@ if (sb_is_modular && !sb_is_evergreen && current_toolchain == cobalt_toolchain) { source_set("cobalt_layer_posix_abi_wrappers") { sources = [ + "cobalt_layer_posix_file_abi_wrappers.cc", "cobalt_layer_posix_mmap_abi_wrappers.cc", "cobalt_layer_posix_pthread_abi_wrappers.cc", "cobalt_layer_posix_socket_abi_wrappers.cc", diff --git a/starboard/shared/modular/cobalt_layer_posix_file_abi_wrappers.cc b/starboard/shared/modular/cobalt_layer_posix_file_abi_wrappers.cc new file mode 100644 index 000000000000..4901f49c4613 --- /dev/null +++ b/starboard/shared/modular/cobalt_layer_posix_file_abi_wrappers.cc @@ -0,0 +1,34 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SB_API_VERSION >= 16 + +#include + +extern "C" { + +off_t __abi_wrap_lseek(int fildes, off_t offset, int whence); + +off_t lseek(int fildes, off_t offset, int whence) { + return __abi_wrap_lseek(fildes, offset, whence); +} + +ssize_t __abi_wrap_read(int fildes, void* buf, size_t nbyte); + +ssize_t read(int fildes, void* buf, size_t nbyte) { + return __abi_wrap_read(fildes, buf, nbyte); +} +} + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc new file mode 100644 index 000000000000..484f0af229ab --- /dev/null +++ b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc @@ -0,0 +1,26 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h" + +#include +#include + +musl_off_t __abi_wrap_lseek(int fildes, musl_off_t offset, int whence) { + return static_cast(lseek(fildes, static_cast(offset), whence)); +} + +ssize_t __abi_wrap_read(int fildes, void* buf, size_t nbyte) { + return read(fildes, buf, nbyte); +} diff --git a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h new file mode 100644 index 000000000000..b2a6433cb2c1 --- /dev/null +++ b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h @@ -0,0 +1,62 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_SHARED_MODULAR_STARBOARD_LAYER_POSIX_FILE_ABI_WRAPPERS_H_ +#define STARBOARD_SHARED_MODULAR_STARBOARD_LAYER_POSIX_FILE_ABI_WRAPPERS_H_ + +#include +#include + +#include "starboard/export.h" + +// The `__abi_wrap_lseek` function converts from the musl's off_t +// type to the platform's off_t which may have different sizes as +// the definition is platform specific. +// The `__abi_wrap_read` function converts ssize_t to int32_t or +// int64_t depending on the platform. +// +// The wrapper is used by all modular builds, including Evergreen. +// +// For Evergreen-based modular builds, we will rely on the exported_symbols.cc +// mapping logic to map calls to file IO functions to `__abi_wrap_` file IO +// functions. +// +// For non-Evergreen modular builds, the Cobalt-side shared library will be +// compiled with code that remaps calls to file IO functions to `__abi_wrap_` +// file IO functions. + +// A matching type for the off_t definition in musl. +typedef int64_t musl_off_t; + +#if SB_IS(ARCH_ARM64) || SB_IS(ARCH_X64) +typedef int64_t ssize_t; +#else +typedef int32_t ssize_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +SB_EXPORT musl_off_t __abi_wrap_lseek(int fildes, + musl_off_t offset, + int whence); + +SB_EXPORT ssize_t __abi_wrap_read(int fildes, void* buf, size_t nbyte); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // STARBOARD_SHARED_MODULAR_STARBOARD_LAYER_POSIX_FILE_ABI_WRAPPERS_H_ diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py index c52fc98bb153..edad7b74e48e 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -97,6 +97,7 @@ 'free', 'freeifaddrs', 'freeaddrinfo', + 'fstat', 'gettimeofday', 'getifaddrs', 'getaddrinfo', From 8f583857562c14311ac9b91e6188d51c9139f6ed Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Fri, 26 Apr 2024 00:13:44 -0700 Subject: [PATCH 8/9] Filter POSIX tests on Android. Change-Id: Ie4502c1809d22fcd892f2b5d6887d9ad62f30df1 --- starboard/android/shared/test_filters.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/starboard/android/shared/test_filters.py b/starboard/android/shared/test_filters.py index 7c90f5484614..ec9f4a34d188 100644 --- a/starboard/android/shared/test_filters.py +++ b/starboard/android/shared/test_filters.py @@ -65,6 +65,11 @@ 'PosixDirectoryOpenTest.SunnyDayStaticContent', 'PosixFileGetPathInfoTest.WorksOnStaticContentDirectories', + # These POSIX tests should be disabled until asset manager starboard + # extension is implemented. + 'PosixFileReadTest.ReadStaticContent', + 'PosixFileSeekTest.FromEndInStaticContentWorks', + # These tests are disabled due to not receiving the kEndOfStream # player state update within the specified timeout. 'SbPlayerGetAudioConfigurationTests/SbPlayerGetAudioConfigurationTest.NoInput/*', From 883c45f4c4a7c42fc0f3ee185d99f0d3fc3c8a56 Mon Sep 17 00:00:00 2001 From: Yijia Zhang Date: Fri, 26 Apr 2024 11:20:26 -0700 Subject: [PATCH 9/9] Add lseek to api leak detector. Change-Id: Ic36a4e91072be7148b821183e73f574b0fb38f39 --- starboard/android/shared/test_filters.py | 3 +- starboard/common/file.cc | 6 +- .../posix_compliance/posix_file_close_test.cc | 4 - .../posix_file_get_info_test.cc | 4 - .../posix_compliance/posix_file_helpers.cc | 70 --------- .../posix_compliance/posix_file_open_test.cc | 4 - .../posix_compliance/posix_file_read_test.cc | 4 - .../posix_compliance/posix_file_seek_test.cc | 4 - ...starboard_layer_posix_file_abi_wrappers.cc | 4 + .../starboard_layer_posix_file_abi_wrappers.h | 1 + .../starboard_layer_posix_stat_abi_wrappers.h | 1 + starboard/shared/uwp/application_uwp.cc | 7 +- .../shared/win32/posix_emu/include/fcntl.h | 4 +- .../win32/posix_emu/include/sys/socket.h | 10 -- .../shared/win32/posix_emu/include/sys/stat.h | 5 + .../shared/win32/posix_emu/include/unistd.h | 13 +- starboard/shared/win32/posix_emu/socket.cc | 11 +- .../api_leak_detector/api_leak_detector.py | 2 + .../musl/src/starboard/network/socket.c | 146 +++++++++++++++++- 19 files changed, 178 insertions(+), 125 deletions(-) delete mode 100644 starboard/nplb/posix_compliance/posix_file_helpers.cc diff --git a/starboard/android/shared/test_filters.py b/starboard/android/shared/test_filters.py index ec9f4a34d188..3d30f3deac2e 100644 --- a/starboard/android/shared/test_filters.py +++ b/starboard/android/shared/test_filters.py @@ -67,7 +67,8 @@ # These POSIX tests should be disabled until asset manager starboard # extension is implemented. - 'PosixFileReadTest.ReadStaticContent', + 'PosixFileGetInfoTest.WorksOnStaticContentFiles', + 'PosixFileReadTest/*.ReadStaticContent', 'PosixFileSeekTest.FromEndInStaticContentWorks', # These tests are disabled due to not receiving the kEndOfStream diff --git a/starboard/common/file.cc b/starboard/common/file.cc index 36e6eec41bce..4ce81e6c2871 100644 --- a/starboard/common/file.cc +++ b/starboard/common/file.cc @@ -14,13 +14,9 @@ #include "starboard/common/file.h" -#ifdef _WIN32 -#include -#else -#include -#endif #include #include +#include #include #include diff --git a/starboard/nplb/posix_compliance/posix_file_close_test.cc b/starboard/nplb/posix_compliance/posix_file_close_test.cc index 7b79b2b00169..ff124f2d41ed 100644 --- a/starboard/nplb/posix_compliance/posix_file_close_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_close_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if SB_API_VERSION >= 16 - // close is partially tested in posix_file_open_test.cc. #include @@ -32,5 +30,3 @@ TEST(PosixFileCloseTest, CloseInvalidFails) { } // namespace } // namespace nplb } // namespace starboard - -#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc index c495508ab091..192fe817cef9 100644 --- a/starboard/nplb/posix_compliance/posix_file_get_info_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_get_info_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if SB_API_VERSION >= 16 - #include #include #include @@ -97,5 +95,3 @@ TEST(PosixFileGetInfoTest, WorksOnStaticContentFiles) { } // namespace } // namespace nplb } // namespace starboard - -#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_helpers.cc b/starboard/nplb/posix_compliance/posix_file_helpers.cc deleted file mode 100644 index 46d0e39862c7..000000000000 --- a/starboard/nplb/posix_compliance/posix_file_helpers.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2024 The Cobalt Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "starboard/nplb/posix_compliance/posix_file_helpers.h" - -#include -#include - -#include -#include -#include - -#include "starboard/configuration_constants.h" -#include "starboard/directory.h" -#include "starboard/file.h" -#include "starboard/shared/posix/file_internal.h" -#include "starboard/system.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace starboard { -namespace nplb { - -// static -std::string ScopedRandomFile::MakeRandomFilePath() { - std::ostringstream filename_stream; - filename_stream << GetTempDir(); - if (!filename_stream.tellp()) { - return ""; - } - - filename_stream << kSbFileSepChar << MakeRandomFilename(); - return filename_stream.str(); -} - -std::string ScopedRandomFile::MakeRandomFile(int length) { - std::string filename = MakeRandomFilePath(); - if (filename.empty()) { - return filename; - } - - int file = open(filename.c_str(), O_CREAT | O_WRONLY); - EXPECT_TRUE(fcntl(file, F_GETFD)); - if (!fcntl(file, F_GETFD)) { - return ""; - } - - char* data = new char[length]; - for (int i = 0; i < length; ++i) { - data[i] = static_cast(i & 0xFF); - } - - bool result = close(file); - EXPECT_TRUE(result) << "Failed to close " << filename; - delete[] data; - return filename; -} - -} // namespace nplb -} // namespace starboard diff --git a/starboard/nplb/posix_compliance/posix_file_open_test.cc b/starboard/nplb/posix_compliance/posix_file_open_test.cc index 97199acd7fa1..5a4c546c9f08 100644 --- a/starboard/nplb/posix_compliance/posix_file_open_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_open_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if SB_API_VERSION >= 16 - #include #include #include @@ -133,5 +131,3 @@ TEST(PosixFileOpenTest, OpenTruncatedDoesNotCreateNonExistingFile) { } // namespace } // namespace nplb } // namespace starboard - -#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_read_test.cc b/starboard/nplb/posix_compliance/posix_file_read_test.cc index fee22ca3bc5f..b6ce49e7957d 100644 --- a/starboard/nplb/posix_compliance/posix_file_read_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_read_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if SB_API_VERSION >= 16 - #include #include #include @@ -269,5 +267,3 @@ TYPED_TEST(PosixFileReadTest, ReadStaticContent) { } // namespace } // namespace nplb } // namespace starboard - -#endif // SB_API_VERSION >= 16 diff --git a/starboard/nplb/posix_compliance/posix_file_seek_test.cc b/starboard/nplb/posix_compliance/posix_file_seek_test.cc index 45d0da1d0078..6473c00f3fde 100644 --- a/starboard/nplb/posix_compliance/posix_file_seek_test.cc +++ b/starboard/nplb/posix_compliance/posix_file_seek_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if SB_API_VERSION >= 16 - #include #include #include @@ -170,5 +168,3 @@ TEST(PosixFileSeekTest, FromEndInStaticContentWorks) { } // namespace } // namespace nplb } // namespace starboard - -#endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc index 484f0af229ab..a02e6a9068bb 100644 --- a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc +++ b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#if SB_API_VERSION >= 16 + #include "starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h" #include @@ -24,3 +26,5 @@ musl_off_t __abi_wrap_lseek(int fildes, musl_off_t offset, int whence) { ssize_t __abi_wrap_read(int fildes, void* buf, size_t nbyte) { return read(fildes, buf, nbyte); } + +#endif // SB_API_VERSION >= 16 diff --git a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h index b2a6433cb2c1..a47269f42825 100644 --- a/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h +++ b/starboard/shared/modular/starboard_layer_posix_file_abi_wrappers.h @@ -37,6 +37,7 @@ // file IO functions. // A matching type for the off_t definition in musl. + typedef int64_t musl_off_t; #if SB_IS(ARCH_ARM64) || SB_IS(ARCH_X64) diff --git a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h index ce08855c5968..cb4fe0999489 100644 --- a/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h +++ b/starboard/shared/modular/starboard_layer_posix_stat_abi_wrappers.h @@ -76,6 +76,7 @@ struct musl_stat { }; SB_EXPORT int __abi_wrap_fstat(int fildes, struct musl_stat* info); + SB_EXPORT int __abi_wrap_stat(const char* path, struct musl_stat* info); #ifdef __cplusplus diff --git a/starboard/shared/uwp/application_uwp.cc b/starboard/shared/uwp/application_uwp.cc index fff54a8eba23..05cf2c605761 100644 --- a/starboard/shared/uwp/application_uwp.cc +++ b/starboard/shared/uwp/application_uwp.cc @@ -24,8 +24,6 @@ #include #include -#include - #include #include #include @@ -58,8 +56,10 @@ #include "starboard/shared/uwp/watchdog_log.h" #include "starboard/shared/uwp/window_internal.h" #include "starboard/shared/win32/thread_private.h" +#include "starboard/shared/win32/time_utils.h" #include "starboard/shared/win32/video_decoder.h" #include "starboard/shared/win32/wchar_utils.h" + #include "starboard/system.h" namespace starboard { @@ -75,6 +75,7 @@ using shared::starboard::NetLogWaitForClientConnected; using shared::uwp::ApplicationUwp; using shared::uwp::RunInMainThreadAsync; using shared::uwp::WaitForResult; +using shared::win32::ConvertUsecToMillisRoundUp; using shared::win32::platformStringToString; using shared::win32::stringToPlatformString; using shared::win32::wchar_tToUTF8; @@ -335,7 +336,7 @@ std::string GetBinaryName() { void OnDeviceAdded(DeviceWatcher ^, DeviceInformation ^) { SB_LOG(INFO) << "DisplayStatusWatcher::OnDeviceAdded"; // We need delay to give time for the display initializing after connect. - usleep(15'000); + Sleep(ConvertUsecToMillisRoundUp(15'000)); MimeSupportabilityCache::GetInstance()->ClearCachedMimeSupportabilities(); diff --git a/starboard/shared/win32/posix_emu/include/fcntl.h b/starboard/shared/win32/posix_emu/include/fcntl.h index 43d70b07daa5..93f9be37b70d 100644 --- a/starboard/shared/win32/posix_emu/include/fcntl.h +++ b/starboard/shared/win32/posix_emu/include/fcntl.h @@ -16,8 +16,8 @@ #define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_FCNTL_H_ #include <../ucrt/fcntl.h> // The Visual Studio version of this same file -#include // Needed for `open`, which is in fcntl.h on POSIX -#include +#include <../ucrt/sys/stat.h> +#include // Needed for `open`, which is in fcntl.h on POSIX #undef open #undef close // in unistd.h on POSIX, and handles both files and sockets diff --git a/starboard/shared/win32/posix_emu/include/sys/socket.h b/starboard/shared/win32/posix_emu/include/sys/socket.h index 2344b7606cc3..39c7e5390c6c 100644 --- a/starboard/shared/win32/posix_emu/include/sys/socket.h +++ b/starboard/shared/win32/posix_emu/include/sys/socket.h @@ -15,7 +15,6 @@ #ifndef STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_SOCKET_H_ #define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_SYS_SOCKET_H_ -#include #include #include #include @@ -70,15 +69,6 @@ int sb_setsockopt(int socket, int option_len); #define setsockopt sb_setsockopt -int sb_fstat(int fd, struct stat* buffer); -#define fstat sb_fstat - -int sb_lseek(int fd, off_t offset, int origin); -#define lseek sb_lseek - -SSIZE_T sb_read(int fildes, void* buf, size_t nbyte); -#define read sb_read - #ifdef __cplusplus } #endif diff --git a/starboard/shared/win32/posix_emu/include/sys/stat.h b/starboard/shared/win32/posix_emu/include/sys/stat.h index 9e031c95ba0b..1b40a221ea54 100644 --- a/starboard/shared/win32/posix_emu/include/sys/stat.h +++ b/starboard/shared/win32/posix_emu/include/sys/stat.h @@ -17,6 +17,7 @@ #include <../ucrt/sys/stat.h> #include +#include #ifdef __cplusplus extern "C" { @@ -28,6 +29,10 @@ extern "C" { typedef int mode_t; +// Implementation in socket.cc +int sb_fstat(int fd, struct stat* buffer); +#define fstat sb_fstat + int sb_mkdir(const char* path, mode_t mode); #undef mkdir #define mkdir sb_mkdir diff --git a/starboard/shared/win32/posix_emu/include/unistd.h b/starboard/shared/win32/posix_emu/include/unistd.h index 63b072fc2a37..9cce6cd430b6 100644 --- a/starboard/shared/win32/posix_emu/include/unistd.h +++ b/starboard/shared/win32/posix_emu/include/unistd.h @@ -15,14 +15,23 @@ #ifndef STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_UNISTD_H_ #define STARBOARD_SHARED_WIN32_POSIX_EMU_INCLUDE_UNISTD_H_ +#include + #ifdef __cplusplus extern "C" { #endif -// This function will handle both files and sockets. The implementation is -// located in socket.cc. +// The implementation of the following functions are located in socket.cc. + +// This function will handle both files and sockets. int close(int fd); +off_t sb_lseek(int fd, off_t offset, int origin); +#define lseek sb_lseek + +ssize_t sb_read(int fildes, void* buf, size_t nbyte); +#define read sb_read + int usleep(unsigned int useconds); #ifdef __cplusplus diff --git a/starboard/shared/win32/posix_emu/socket.cc b/starboard/shared/win32/posix_emu/socket.cc index 60ba27fe22c8..75ff40840cd6 100644 --- a/starboard/shared/win32/posix_emu/socket.cc +++ b/starboard/shared/win32/posix_emu/socket.cc @@ -17,7 +17,6 @@ #include #include // Needed for file-specific `_close`. #include -#include #include // Our version that declares generic `close`. #include #undef NO_ERROR // http://b/302733082#comment15 @@ -290,20 +289,20 @@ int close(int fd) { return _close(handle.file); } -int sb_lseek(int fd, off_t offset, int origin) { +off_t sb_lseek(int fd, off_t offset, int origin) { FileOrSocket handle = handle_db_get(fd, false); if (!handle.is_file) { return -1; } - return lseek(handle.file, offset, origin); + return _lseek(handle.file, offset, origin); } -SSIZE_T sb_read(int fd, void* buf, size_t nbyte) { +ssize_t sb_read(int fd, void* buf, size_t nbyte) { FileOrSocket handle = handle_db_get(fd, false); if (!handle.is_file) { return -1; } - return read(handle.file, buf, nbyte); + return _read(handle.file, buf, nbyte); } int sb_bind(int socket, const struct sockaddr* address, socklen_t address_len) { @@ -471,7 +470,7 @@ int sb_fstat(int fd, struct stat* buffer) { if (!handle.is_file) { return -1; } - return fstat(handle.file, buffer); + return _fstat(handle.file, (struct _stat*)buffer); } } // extern "C" diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py index edad7b74e48e..6a23ff89b6fc 100755 --- a/starboard/tools/api_leak_detector/api_leak_detector.py +++ b/starboard/tools/api_leak_detector/api_leak_detector.py @@ -104,6 +104,7 @@ 'gmtime_r', 'inet_ntop', 'listen', + 'lseek', 'malloc', 'posix_memalign', 'recv', @@ -121,6 +122,7 @@ 'mprotect', 'msync', 'mkdir', + 'read', 'sched_yield', 'stat', 'pthread_cond_broadcast', diff --git a/third_party/musl/src/starboard/network/socket.c b/third_party/musl/src/starboard/network/socket.c index 6b29b63bd657..23b633fe18d7 100644 --- a/third_party/musl/src/starboard/network/socket.c +++ b/third_party/musl/src/starboard/network/socket.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -28,8 +29,8 @@ #include "starboard/file.h" #include "starboard/socket.h" #include "starboard/system.h" -#include "starboard/file.h" #include "starboard/time.h" +#include "starboard/types.h" #include "../pthread/pthread.h" // Internal database function to convert SbSocket/SbFile object to @@ -151,6 +152,12 @@ static int get(int key, bool take, FileOrSocket** valuePtr) { return status; } +static SB_C_FORCE_INLINE time_t WindowsUsecToTimeT(int64_t time) { + int64_t posix_time = time - 11644473600000000ULL; + posix_time = posix_time / 1000000; + return posix_time; +} + int TranslateSocketErrnoSbToPosix(SbSocketError sbError) { switch (sbError) { case kSbSocketOk: @@ -214,6 +221,73 @@ int ConvertSocketAddressSbToPosix(const SbSocketAddress* sbAddress, struct socka // The exported POSIX APIs // +int fstat(int fildes, struct stat* buf) { + if (fildes < 0) { + errno = EBADF; + return -1; + } + + FileOrSocket* fileOrSock = NULL; + if (get(fildes, false, &fileOrSock) != 0) { + errno = EBADF; + return -1; + } + + if (fileOrSock == NULL || !fileOrSock->is_file) { + errno = EBADF; + return -1; + } + + SbFileInfo info; + if (!SbFileGetInfo(fileOrSock->file, &info)) { + return -1; + } + + buf->st_mode = 0; + if (info.is_directory) { + buf->st_mode = S_IFDIR; + } else if (info.is_symbolic_link) { + buf->st_mode = S_IFLNK; + } + buf->st_ctime = WindowsUsecToTimeT(info.creation_time); + buf->st_atime = WindowsUsecToTimeT(info.last_accessed); + buf->st_mtime = WindowsUsecToTimeT(info.last_modified); + buf->st_size = info.size; + + return 0; +} + +off_t lseek(int fildes, off_t offset, int whence) { + if (fildes < 0) { + errno = EBADF; + return -1; + } + + FileOrSocket* fileOrSock = NULL; + if (get(fildes, false, &fileOrSock) != 0) { + errno = EBADF; + return -1; + } + + if (fileOrSock == NULL || !fileOrSock->is_file) { + errno = EBADF; + return -1; + } + + SbFileWhence sbWhence; + if (whence == SEEK_SET) { + sbWhence = kSbFileFromBegin; + } else if (whence == SEEK_CUR) { + sbWhence = kSbFileFromCurrent; + } else if (whence == SEEK_END) { + sbWhence = kSbFileFromEnd; + } else { + return -1; + } + + return (off_t)SbFileSeek(fileOrSock->file, sbWhence, (int64_t)offset); +} + int open(const char* path, int oflag, ...) { bool out_created; SbFileError out_error; @@ -226,11 +300,51 @@ int open(const char* path, int oflag, ...) { memset(value, 0, sizeof(struct FileOrSocket)); value->is_file = true; - // TODO: b/302715109 map posix flags to SB file flags - int open_flags = 0; - // O_APPEND, O_ASYNC, O_CLOEXEC, O_CREAT, O_DIRECT, O_DIRECTORY, O_DSYNC - // O_EXCL, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_NOFOLLOW, - // O_NONBLOCK or O_NDELAY, O_PATH, O_SYNC, O_TMPFILE, O_TRUNC + int sbFileFlags = 0; + int accessModeFlag = 0; + + if ((oflag & O_ACCMODE) == O_RDONLY) { + accessModeFlag |= kSbFileRead; + if (oflag == O_RDONLY) { + sbFileFlags = kSbFileOpenOnly; + } + } else if ((oflag & O_ACCMODE) == O_WRONLY) { + accessModeFlag |= kSbFileWrite; + oflag &= ~O_WRONLY; + } else if ((oflag & O_ACCMODE) == O_RDWR) { + accessModeFlag |= kSbFileRead | kSbFileWrite; + oflag &= ~O_RDWR; + } else { + // Applications shall specify exactly one of the first three file access + // modes. + out_error = kSbFileErrorFailed; + return -1; + } + + if (oflag & O_CREAT && oflag & O_EXCL) { + sbFileFlags = kSbFileCreateOnly; + oflag &= ~(O_CREAT | O_EXCL); + } + if (oflag & O_CREAT && oflag & O_TRUNC) { + sbFileFlags = kSbFileCreateAlways; + oflag &= ~(O_CREAT | O_TRUNC); + } + if (oflag & O_CREAT) { + sbFileFlags = kSbFileOpenAlways; + oflag &= ~O_CREAT; + } + if (oflag & O_TRUNC) { + sbFileFlags = kSbFileOpenTruncated; + oflag &= ~O_TRUNC; + } + + // SbFileOpen does not support any other combination of flags. + if (oflag || !sbFileFlags) { + out_error = kSbFileErrorFailed; + return -1; + } + + int open_flags = sbFileFlags | accessModeFlag; value->file = SbFileOpen(path, open_flags, &out_created, &out_error); if (!SbFileIsValid(value->file)){ @@ -248,6 +362,26 @@ int open(const char* path, int oflag, ...) { return result; } +ssize_t read(int fildes, void* buf, size_t nbyte) { + if (fildes < 0) { + errno = EBADF; + return -1; + } + + FileOrSocket* fileOrSock = NULL; + if (get(fildes, false, &fileOrSock) != 0) { + errno = EBADF; + return -1; + } + + if (fileOrSock == NULL || !fileOrSock->is_file) { + errno = EBADF; + return -1; + } + + return (ssize_t)SbFileRead(fileOrSock->file, buf, (int)nbyte); +} + int socket(int domain, int type, int protocol){ int address_type, socket_protocol; switch (domain){