[Filesystem] Querying a card reader can throw on Windows

Hi, Beman. If I understand correctly, the idiom to check whether a directory exists using Boost.Filesystem is if (fs::exists(path) && fs::is_directory(path)) Under normal conditions the code above shouldn't throw, right? One of our users reports that this code does, however, throw when it is used on Windows to query a card reader that has a drive letter J: assigned to it. Below is a diagnostic program that attempts to query a nonexistent "J:\foo". Executing it, our user finds: 1. If no drive is associated with J: then the program outputs nothing. 2. If an empty drive is associated with J: Exception caught: boost::filesystem::is_directory: "J:\foo": The device is not ready. Assertion failed: false file ekkehart.cpp, line 40 3. If the drive contains a disk the program outputs nothing. He goes on to say: The problem described disappears if I do one of the following: 1. Reassign another letter to the smart cars slot (such that J: is not assigned to any drive) 2. Reassign J: to a used slot (in my case the compact flash slot) and insert a card. 3. Remove the card reader. Conclusion: You should have either no drive assigned to J: or a drive with an inserted medium. This is with the current release of Boost, 1.33.1. Is this a known problem (is there a workaround) or have we stumbled upon a bug? Kind regards, Angus /* Compiled with g++ -fno-exceptions -Iboost -o ekkehart ekkehart.cpp \ -Lbuild/boost/libs/filesystem/src/.libs -lboost_filesystem */ #include <boost/filesystem/operations.hpp> #include <boost/filesystem/path.hpp> #include <cassert> #include <cstdlib> #include <exception> #include <iostream> namespace fs = boost::filesystem; int main() { fs::path const path("J:/foo", fs::no_check); if (fs::exists(path) && fs::is_directory(path)) std::cout << path.native_directory_string() << "is a directory" << std::endl; return 0; } namespace boost { void throw_exception(std::exception const & e) { std::cerr << "Exception caught:\n" << e.what() << std::endl; assert(false); } void assertion_failed(char const * expr, char const * function, char const * file, long line) { std::cerr << "Assertion triggered in " << function << " by failing check \"" << expr << "\"" << " in file " << file << ":" << line << std::endl; ::abort(); } } // namespace boost

Angus Leeming <angus.leeming <at> btopenworld.com> writes:
If I understand correctly, the idiom to check whether a directory exists using Boost.Filesystem is
if (fs::exists(path) && fs::is_directory(path))
Under normal conditions the code above shouldn't throw, right?
Welcome to the wonderful world of filesystem exceptions. Your code will throw on many conditions. Some I know from the top of my head are (on windows): 1. path is a system file like pagefile.sys 2. the user don't have access to an element in the path. I have tried to point out several times that filesystem operations can and will throw. Production code without try/catch around ALL filesystem operations will cause problems (and don't assume that the catch statement should only handle racing and filesystem corruption exceptions). I think the documentation should have big red letters saying: - Never use any filesystem operation in production code without proper try/catch guards (or use the non-throwing versions in 1.34). - Never assume that an operations "will not throw under normal conditions" because it will. A good way to test your code is to run the application as a non-administrator and enter "c:\" and "C:\pagefile.sys" as test paths.
participants (2)
-
Angus Leeming
-
Martin Adrian