Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cpp/src/file/local_random_access_read_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,23 @@ int LocalRandomAccessReadFile::open(const std::string& file_path) {
(preopen_stat.st_mode & _S_IFMT) != _S_IFREG) {
return E_INVALID_PATH;
}
#endif
#ifndef _WIN32
// POSIX open(O_RDONLY) blocks on a FIFO until a writer appears, and
// succeeds on directories/device files. Preflight with stat() (which
// follows symlinks) so non-regular paths fail fast with the same stable
// E_INVALID_PATH code the post-open fstat() check below produces, instead
// of hanging forever. If stat() itself fails (missing file, dangling
// symlink), fall through to the normal open() path so those continue to
// report E_FILE_OPEN_ERR.
// Close the stat/open race: regular files ignore O_NONBLOCK, while a FIFO
// replacement cannot block before the descriptor check below.
flags |= O_NONBLOCK;
struct stat preopen_stat;
if (::stat(file_path_.c_str(), &preopen_stat) == 0 &&
!S_ISREG(preopen_stat.st_mode)) {
return E_INVALID_PATH;
}
#endif
fd_ = file_internal::open_utf8(file_path_, flags);
if (fd_ < 0) {
Expand Down
18 changes: 18 additions & 0 deletions cpp/test/tools/model_format_e2e_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,24 @@ TEST(IndependentFixtures, EmptyTreeAndInputFailuresHaveExactDiagnostics) {
expect_cli_exact(input_args(command, "."), 2, "",
"Error: cannot open .: invalid path (code 37)\n");
}
#ifndef _WIN32
// A FIFO (named pipe) is a special file, not a TsFile. POSIX
// open(O_RDONLY) would otherwise block until a writer appears, so the
// reader must preflight the file type and fail fast with the same stable
// diagnostic instead of hanging.
{
const std::string fifo = tsfile_cli_test::unique_temp_path(
"tsfile_cli_fifo_input", ".tsfile");
ASSERT_EQ(mkfifo(fifo.c_str(), 0600), 0);
for (const std::string& command : commands) {
std::remove("tsfile_cli_input_error.csv");
expect_cli_exact(
input_args(command, fifo), 2, "",
"Error: cannot open " + fifo + ": invalid path (code 37)\n");
}
std::remove(fifo.c_str());
}
#endif
std::remove("tsfile_cli_input_error.csv");
}

Expand Down
Loading