Skip to content

Instantly share code, notes, and snippets.

@lukem
Created January 6, 2019 00:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukem/693f03e4d0ece63e16c05ca218612d7f to your computer and use it in GitHub Desktop.
Save lukem/693f03e4d0ece63e16c05ca218612d7f to your computer and use it in GitHub Desktop.
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
Copy link
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
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