Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: fix contents_first with root symlink #165

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

danielparks
Copy link

This fixes two incorrect behaviors when contents_first is on and the root path is a symlink:

  1. The root path was returned first in the iterator instead of last.
  2. Some subdirectories were returned out of order.

The issue was that root symlinks were returned immediately rather than being pushed onto the deferred_dirs vec. That lead to deferred_dirs and depth being out of sync, which lead to deferred directories being processed one ascent too late.

This also changes the internal handling of the same_file_system option slightly. Previously, if a directory was found to be on a different file system it would not be pushed to the stack, but it would be pushed to the deferred list. This did not matter because in those cases handle_entry() would return to next(), which would immediately pop the directory off the deferred list and return it. This ensures that the directory is returned immediately, and is not pushed to either the stack or the deferred list. (I think this makes the code clearer.)

Fixes: #163


Unfortunately, writing tests for same_file_system would involve either adding a FS indirection layer (oh boy), or… calling out to sudo, I guess? Or maybe having a separate script to set things up? I did some testing manually and I’m convinced that it still works the same way it previously did, and that it is correct.

See #164 for more tests related to this.

I haven’t tested this on Windows, but I have maintained the same checks for symlinks and dirs, so I’m pretty sure it should be fine. Sorry, I just don’t have a good way to test it right now.

There are a couple of other versions of this fix in defer_root_symlink_separate_commits. In particular, the original version combined the if self.opts.follow_links in with the let should_descend = if , but I felt that it was weird to have dent = itry!(self.follow(dent)) inside an if block that was nominally for determining the value of should_descend.

@danielparks
Copy link
Author

Sorry, that was kind of a lot of text.

This fixes two incorrect behaviors when `contents_first` is on and the
root path is a symlink:

  1. The root path was returned first in the iterator instead of last.
  2. Some subdirectories were returned out of order.

The issue was that root symlinks were returned immediately rather than
being pushed onto the `deferred_dirs` vec. That lead to `deferred_dirs`
and `depth` being out of sync, which lead to deferred directories being
processed one ascent too late.

This also changes the internal handling of the `same_file_system` option
slightly. Previously, if a directory was found to be on a different file
system it would _not_ be pushed to the stack, but it _would_ be pushed
to the deferred list. This did not matter because in those cases
`handle_entry()` would return to `next()`, which would immediately pop
the directory off the deferred list and return it. This ensures that the
directory is returned immediately, and is not pushed to either the stack
or the deferred list. (I think this makes the code clearer.)

Fixes: BurntSushi#163
@danielparks danielparks force-pushed the defer_root_symlink branch from 9fa3585 to 18d6c79 Compare May 29, 2023 15:35
@danielparks
Copy link
Author

Ping @BurntSushi. Anything I can do on this or #164? I just rebased. Of course, I realize you probably have other priorities. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parent directory appears out of order with contents_first(true) in certain circumstances
1 participant