Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
boost 1.56 changed Boost.Filesystem recursive_directory_iterator
/*
* Workaround Boost.Filesystem V3 behaviour change in boost 1.56.
* See original at http://thisthread.blogspot.com/2011/07/using-recursivedirectoryiterator.html
*/
void plainListTree(boost::filesystem::path path) // 1.
{
dump(path, 0);
boost::filesystem::recursive_directory_iterator it = createRIterator(path);
boost::filesystem::recursive_directory_iterator end;
while(it != end) // 2.
{
const std::string curPath(it->path().string());
dump(*it, it.level()); // 3.
if(boost::filesystem::is_directory(*it) && boost::filesystem::is_symlink(*it)) // 4.
it.no_push();
// advance it
try
{
++it; // 5.
}
catch (boost::filesystem::filesystem_error & e)
{
std::cout << "warn: " << curPath << ": " << e.what() << std::endl;
/*
* boost 1.56 changed the behaviour of the recursive_directory_iterator in two ways:
* 1. The iterator is advanced before the error is raised (exception thrown),
* so the no_push() workaround isn't required. If that workaround is used,
* the next path is incorrectly skipped.
* 2. Because of (1), accessing it->path().string() in error handling
* prints the _next_ path, not the erroneous one.
* Handle the older behaviour below.
*/
#if BOOST_VERSION < 105600
try
{
it.no_push(); // 6.
++it;
}
catch (boost::filesystem::filesystem_error & e)
{
std::cout << "fatal error: " << curPath << ": " << e.what() << std::endl;
throw;
}
#endif // BOOST_VERSION < 105600
}
}
}
@lukem

This comment has been minimized.

Copy link
Owner Author

lukem commented Jan 6, 2019

Background

The original code was in http://thisthread.blogspot.com.au/2011/07/using-recursivedirectoryiterator.html

The pattern worked fine with boost 1.41 (Boost.Filesystem V2) on CentOS 6. However, I experienced a behaviour change when using boost 1.64 (Boost.Filesystem V3) on macOS 10.12.

After a lot of debugging, it appears that boost 1.56 changed the behaviour of the recursive_directory_iterator in two ways, one of which directly affects the pattern: (Boost.Filesystem V3 was made the default in boost 1.46, and this behaviour change wasn't made until 1.56):

  1. The iterator is advanced before the error is raised (exception thrown), so the no_push() workaround isn't required. If that workaround is used, the next path is incorrectly skipped.
  2. Because of (1), accessing it->path().string() in error handling prints the next path, not the erroneous one.

Fix

  1. Cache it->path().string() for use in error messages;
  2. Only do the it.no_push();++it if boost < 1.56.
@egalli64

This comment has been minimized.

Copy link

egalli64 commented Jan 8, 2019

I have put a link to this gist in the blog. Thank you, Luke!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.