diff --git a/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 7cdf5fe462547b7bdfe65907a8e2353cbb3a36f0..168e09c7d2c7eca882fd01997bccb4d0e2bac5ae 100644 --- a/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/bsd/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -507,6 +507,11 @@ zfs_read(vnode_t *vp, struct file* fp, uio_t *uio, int ioflag) xuio_t *xuio = NULL; #endif + // Return EISDIR when reading from a directory, as Linux does. + if (vp->v_type == VDIR) { + return EISDIR; + } + ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); os = zfsvfs->z_os; diff --git a/build.mk b/build.mk index 0bdb0144f4e39d50761faabef0010919ee989e76..c1d77d0965bd1699b47e6e14ff8af4457855a885 100644 --- a/build.mk +++ b/build.mk @@ -240,6 +240,7 @@ tests += tests/tst-pipe.so tests += tests/tst-yield.so tests += tests/misc-ctxsw.so tests += tests/tst-readdir.so +tests += tests/tst-read.so tests += tests/tst-remove.so tests += tests/misc-wake.so tests += tests/tst-epoll.so diff --git a/tests/tst-read.cc b/tests/tst-read.cc new file mode 100644 index 0000000000000000000000000000000000000000..6147457f8d53190e50292718d6d416a8023183ea --- /dev/null +++ b/tests/tst-read.cc @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Cloudius Systems, Ltd. + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ +// To compile on Linux, use: g++ -g -pthread -std=c++11 tests/tst-read.cc + +#include <sys/timerfd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> +#include <unistd.h> + +#include <iostream> +#include <chrono> +#include <thread> + +#include <errno.h> +static int tests = 0, fails = 0; + +template<typename T> +bool do_expect(T actual, T expected, const char *actuals, const char *expecteds, const char *file, int line) +{ + ++tests; + if (actual != expected) { + fails++; + std::cout << "FAIL: " << file << ":" << line << ": For " << actuals + << " expected " << expecteds << "(" << expected << "), saw " + << actual << ".\n"; + return false; + } + std::cout << "OK: " << file << ":" << line << ".\n"; + return true; +} +template<typename T> +bool do_expectge(T actual, T expected, const char *actuals, const char *expecteds, const char *file, int line) +{ + ++tests; + if (actual < expected) { + fails++; + std::cout << "FAIL: " << file << ":" << line << ": For " << actuals + << " expected >=" << expecteds << ", saw " << actual << ".\n"; + return false; + } + std::cout << "OK: " << file << ":" << line << ".\n"; + return true; +} +#define expect(actual, expected) do_expect(actual, expected, #actual, #expected, __FILE__, __LINE__) +#define expectge(actual, expected) do_expectge(actual, expected, #actual, #expected, __FILE__, __LINE__) +#define expect_errno(call, experrno) ( \ + do_expect((long)(call), (long)-1, #call, "-1", __FILE__, __LINE__) && \ + do_expect(errno, experrno, #call " errno", #experrno, __FILE__, __LINE__) ) +#define expect_success(var, call) \ + errno = 0; \ + var = call; \ + do_expectge(var, 0, #call, "0", __FILE__, __LINE__); \ + do_expect(errno, 0, #call " errno", "0", __FILE__, __LINE__); + +int main() +{ + // Test how reading from a directory fails with EISDIR, as in Linux. + int fd; + expect_success(fd, open("/tmp", O_RDONLY)); + char buf[1024]; + expect_errno(read(fd, buf, 10), EISDIR); + + std::cout << "SUMMARY: " << tests << " tests, " << fails << " failures\n"; + return fails == 0 ? 0 : 1; +}