diff --git a/cpp/src/io/utilities/data_sink.cpp b/cpp/src/io/utilities/data_sink.cpp index aaad68619ae..0b14d060b05 100644 --- a/cpp/src/io/utilities/data_sink.cpp +++ b/cpp/src/io/utilities/data_sink.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2023, NVIDIA CORPORATION. + * Copyright (c) 2020-2024, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ namespace cudf { namespace io { + /** * @brief Implementation class for storing data into a local file. */ @@ -34,7 +35,7 @@ class file_sink : public data_sink { explicit file_sink(std::string const& filepath) { _output_stream.open(filepath, std::ios::out | std::ios::binary | std::ios::trunc); - CUDF_EXPECTS(_output_stream.is_open(), "Cannot open output file"); + if (!_output_stream.is_open()) { detail::throw_on_file_open_failure(filepath, true); } if (detail::cufile_integration::is_kvikio_enabled()) { _kvikio_file = kvikio::FileHandle(filepath, "w"); diff --git a/cpp/src/io/utilities/file_io_utilities.cpp b/cpp/src/io/utilities/file_io_utilities.cpp index 28eae8b8e97..63c1114c9ce 100644 --- a/cpp/src/io/utilities/file_io_utilities.cpp +++ b/cpp/src/io/utilities/file_io_utilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023, NVIDIA CORPORATION. + * Copyright (c) 2021-2024, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "file_io_utilities.hpp" #include #include @@ -20,7 +21,10 @@ #include #include +#include +#include +#include #include #include @@ -28,23 +32,42 @@ namespace cudf { namespace io { namespace detail { -size_t get_file_size(int file_descriptor) +[[noreturn]] void throw_on_file_open_failure(std::string const& filepath, bool is_create) { - struct stat st; - CUDF_EXPECTS(fstat(file_descriptor, &st) != -1, "Cannot query file size"); - return static_cast(st.st_size); + // save errno because it may be overwritten by subsequent calls + auto const err = errno; + + if (auto const path = std::filesystem::path(filepath); is_create) { + CUDF_EXPECTS(std::filesystem::exists(path.parent_path()), + "Cannot create output file; directory does not exist"); + + } else { + CUDF_EXPECTS(std::filesystem::exists(path), "Cannot open file; it does not exist"); + } + + std::array error_msg_buffer; + auto const error_msg = strerror_r(err, error_msg_buffer.data(), 1024); + CUDF_FAIL("Cannot open file; failed with errno: " + std::string{error_msg}); } -file_wrapper::file_wrapper(std::string const& filepath, int flags) - : fd(open(filepath.c_str(), flags)), _size{get_file_size(fd)} +[[nodiscard]] int open_file_checked(std::string const& filepath, int flags, mode_t mode) { - CUDF_EXPECTS(fd != -1, "Cannot open file " + filepath); + auto const fd = open(filepath.c_str(), flags, mode); + if (fd == -1) { throw_on_file_open_failure(filepath, flags & O_CREAT); } + + return fd; +} + +[[nodiscard]] size_t get_file_size(int file_descriptor) +{ + struct stat st; + CUDF_EXPECTS(fstat(file_descriptor, &st) != -1, "Cannot query file size"); + return static_cast(st.st_size); } file_wrapper::file_wrapper(std::string const& filepath, int flags, mode_t mode) - : fd(open(filepath.c_str(), flags, mode)), _size{get_file_size(fd)} + : fd(open_file_checked(filepath.c_str(), flags, mode)), _size{get_file_size(fd)} { - CUDF_EXPECTS(fd != -1, "Cannot open file " + filepath); } file_wrapper::~file_wrapper() { close(fd); } diff --git a/cpp/src/io/utilities/file_io_utilities.hpp b/cpp/src/io/utilities/file_io_utilities.hpp index b55dd3b1583..90bf591fe0c 100644 --- a/cpp/src/io/utilities/file_io_utilities.hpp +++ b/cpp/src/io/utilities/file_io_utilities.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2023, NVIDIA CORPORATION. + * Copyright (c) 2021-2024, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,16 +34,17 @@ namespace cudf { namespace io { namespace detail { +[[noreturn]] void throw_on_file_open_failure(std::string const& filepath, bool is_create); + /** * @brief Class that provides RAII for file handling. */ class file_wrapper { - int fd = -1; - size_t _size; + int fd = -1; + size_t _size = 0; public: - explicit file_wrapper(std::string const& filepath, int flags); - explicit file_wrapper(std::string const& filepath, int flags, mode_t mode); + explicit file_wrapper(std::string const& filepath, int flags, mode_t mode = 0); ~file_wrapper(); [[nodiscard]] auto size() const { return _size; } [[nodiscard]] auto desc() const { return fd; }