Boost C++ Libraries: Ticket #5652: recursive_directory_iterator fails on cyclic symbolic links https://svn.boost.org/trac10/ticket/5652 <p> recursive_directory_iterator throws 'Too many levels of symbolic links' on bad, yet correct symbolic links. To reproduce on Linux: </p> <p> $ ln -s mybadlink mybadlink </p> <p> iterating through directory containing 'mybadlink' (with symlink_option::none) results in exception: </p> <p> boost::filesystem::status: Too many levels of symbolic links: "./mybadlink" </p> <p> Also tested on boost 1.47.0-beta1 </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/5652 Trac 1.4.3 Daniel Aarno <macbishop@…> Sat, 15 Oct 2011 19:28:52 GMT attachment set https://svn.boost.org/trac10/ticket/5652 https://svn.boost.org/trac10/ticket/5652 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">bug5652.diff</span> </li> </ul> <p> Fix for bug 5652: Check if file is symbolic link before stat:ing it during recursion (an not the other way around) </p> Ticket Daniel Aarno <macbishop@…> Sat, 15 Oct 2011 19:32:32 GMT <link>https://svn.boost.org/trac10/ticket/5652#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5652#comment:1</guid> <description> <p> I can confirm this issue and there is an easy fix. To reproduce and test the issue the following simple program that counts the files (recursively) in a directory can be used on a directory containing the "symlink to self" as described by Geurt. </p> <p> #include &lt;string&gt; #include &lt;iostream&gt; </p> <p> #include &lt;boost/filesystem.hpp&gt; </p> <p> int ftw(const std::string &amp;root) { </p> <blockquote> <p> using namespace boost::filesystem; typedef recursive_directory_iterator walker; int count = 0; for (walker w(root); w != walker(); ++w) </p> <blockquote> <p> ++count; </p> </blockquote> </blockquote> <blockquote> <p> return count; </p> </blockquote> <p> } </p> <p> int main (int argc, const char <strong>argv) { </strong></p> <blockquote> <p> int count = ftw(argv<a class="changeset" href="https://svn.boost.org/trac10/changeset/1" title="Import core sources for SVNmanger 0.38 ">[1]</a>); std::cout &lt;&lt; count &lt;&lt; std::endl; </p> </blockquote> <p> } </p> <p> The problem is in the increment method in recur_dir_itr_imp. It checks the file with is_directory, which will end up in a "stat" call on the file. Of course if the file is a symlink to itself stat will try to follow the link indefinitely (since it will try to deference the symlink until a real file is found). This causes stat to generate an ELOOP error and the exception is thrown. </p> <p> The solution is to not check if the file is a directory if it is a symlink - unless of course we are following symlinks during recursion, in which case the exception should occur. We can test this by adding symlink_option::recurse as an option to the walker constructor in the above example. </p> </description> <category>Ticket</category> </item> <item> <author>Daniel Aarno <macbishop@…></author> <pubDate>Sat, 15 Oct 2011 19:41:59 GMT</pubDate> <title>cc set https://svn.boost.org/trac10/ticket/5652#comment:2 https://svn.boost.org/trac10/ticket/5652#comment:2 <ul> <li><strong>cc</strong> <span class="trac-author">macbishop@…</span> added </li> </ul> <p> For efficiency reasons it would also be a good idea to first check for symlink_option::recurse and *then* for is_symlink, since if we are following symlinks we will not have to do the (expensive) call to lstat and we will only do an integer comparision. </p> Ticket Daniel Aarno <macbishop@…> Sat, 15 Oct 2011 19:45:08 GMT attachment set https://svn.boost.org/trac10/ticket/5652 https://svn.boost.org/trac10/ticket/5652 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">bug5652-perf-opt.diff</span> </li> </ul> <p> Performance optimized patch for bug 5652: Check if file is symbolic link before stat:ing it during recursion (an not the other way around) but first check if we are following symlinks </p> Ticket benjamin.kircher@… Sun, 15 Jan 2012 20:03:10 GMT <link>https://svn.boost.org/trac10/ticket/5652#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5652#comment:3</guid> <description> <p> Just walked into this with 1.48. +1 </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Beman Dawes</dc:creator> <pubDate>Tue, 17 Jan 2012 14:36:44 GMT</pubDate> <title>status changed https://svn.boost.org/trac10/ticket/5652#comment:4 https://svn.boost.org/trac10/ticket/5652#comment:4 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/5652#comment:1" title="Comment 1">Daniel Aarno &lt;macbishop@…&gt;</a>: </p> <blockquote class="citation"> <p> I can confirm this issue and there is an easy fix. To reproduce and test the issue the following simple program that counts the files (recursively) in a directory can be used on a directory containing the "symlink to self" as described by Geurt. </p> <p> #include &lt;string&gt; #include &lt;iostream&gt; </p> <p> #include &lt;boost/filesystem.hpp&gt; </p> <p> int ftw(const std::string &amp;root) { </p> <blockquote> <p> using namespace boost::filesystem; typedef recursive_directory_iterator walker; int count = 0; for (walker w(root); w != walker(); ++w) </p> <blockquote> <p> ++count; </p> </blockquote> </blockquote> <blockquote> <p> return count; </p> </blockquote> <p> } </p> <p> int main (int argc, const char <strong>argv) { </strong></p> <blockquote> <p> int count = ftw(argv<a class="changeset" href="https://svn.boost.org/trac10/changeset/1" title="Import core sources for SVNmanger 0.38 ">[1]</a>); std::cout &lt;&lt; count &lt;&lt; std::endl; </p> </blockquote> <p> } </p> </blockquote> <p> Thanks for the test program! Providing a test program is a very effective way to communicative exactly what problem you are having, and prevents me from chasing my tail around in circles. </p> <p> On Windows the program throws with a message "The name of the file cannot be resolved by the system". I haven't looked at your patch yet, but wanted to thank you for the test case first, </p> <p> --Beman </p> Ticket macbishop@… Tue, 17 Jan 2012 14:51:50 GMT <link>https://svn.boost.org/trac10/ticket/5652#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5652#comment:5</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/5652#comment:4" title="Comment 4">bemandawes</a>: </p> <blockquote class="citation"> <p> On Windows the program throws with a message "The name of the file cannot be resolved by the system". I haven't looked at your patch yet, but wanted to thank you for the test case first </p> </blockquote> <p> Thanks for looking into this. To clarify, the test case takes as its first argument a path to a directory containing the recursive symlink, so you need to: </p> <p> 1) Setup a directory with a symlink that points to itself (not sure how to do it on windows) 2) Then run the test case, with the path to the directory given as the only argument, e.g. ./a.out thedir </p> <p> Let me know if you have any questions or suggestions on the test-case or patches. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Beman Dawes</dc:creator> <pubDate>Sun, 22 Jan 2012 16:14:05 GMT</pubDate> <title>status, milestone changed; resolution set https://svn.boost.org/trac10/ticket/5652#comment:6 https://svn.boost.org/trac10/ticket/5652#comment:6 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.49.0</span> </li> </ul> <p> Fixed by changeset 76556. </p> <p> Thanks, all! </p> <p> --Beman </p> Ticket