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

Paths on Windows are invalid #78

Open
71 opened this issue Jan 7, 2020 · 12 comments
Open

Paths on Windows are invalid #78

71 opened this issue Jan 7, 2020 · 12 comments
Labels
windows Windows specific problem

Comments

@71
Copy link

71 commented Jan 7, 2020

Describe the bug
On Windows, the extended path with UNC prefix are used to canonicalize paths (e.g in the root directory at the top, or in output of commands). This causes issues

To Reproduce
Using the following Powershell Core function, try to :cd into a directory.

function br
{
    $TempFile = New-TemporaryFile
    broot.exe --outcmd $TempFile $Args

    if (!$?)
    {
        Remove-Item -Force $TempFile
        return $LASTEXITCODE
    }

    $CommandToExecute = Get-Content $TempFile
    Remove-Item -Force $TempFile
    Invoke-Expression $CommandToExecute
}

An error will be shown, indicating that the path \\?\A:\Foo does not exist (even though A:\Foo does exist).

Expected behavior
Normal (usable) links with no UNC prefix should be used, since most commands do not support those prefixes.

Configuration

  • OS: Windows
  • Version: 10.0.18362

Additional context
As first reported here, the problem is that Broot calls std::fs::canonicalize, which returns a path like \\?\C:\Users\71, instead of C:\Users\71. Therefore using :cd inside Broot will write a command cd '\\?\A:\foo', which will confuse PowerShell (and most commands in general).

A workaround is to execute $Command.Replace('\\?\', '') instead of $Command.

In the end, the script I ended up using is:

function br
{
    $TempFile = New-TemporaryFile
    broot.exe --outcmd $TempFile $Args

    if (!$?)
    {
        Remove-Item -Force $TempFile
        return $LASTEXITCODE
    }

    $CommandToExecute = Get-Content $TempFile
    Remove-Item -Force $TempFile
    Invoke-Expression $CommandToExecute.Replace('\\?\', '')
}

However, it looks like this does not work in all cases. This crate attempts to make the transformation in a smart way, but I wonder what should happen when it judges that the UNC prefix cannot be stripped.

@Canop
Copy link
Owner

Canop commented Jan 8, 2020

I can't test on windows so I'll need your help for that (you already wrote a beautiful bug report).

Do you think we could just solve the problem by issuing our own canonicalization at broot launch?

Something like this:

#[cfg(not(windows))]
fn canonicalize_root(root: &Path) -> io::Result<PathBuf> {
    root.canonicalize()
}

#[cfg(windows)]
fn canonicalize_root(root: &Path) -> io::Result<PathBuf> {
    Ok(
        if root.is_relative() {
            env::current_dir()?.join(root)
        } else {
            root.to_path_buf()
        }
    )
}

(maybe also solving links but there's probably not much more to do)

Canop added a commit that referenced this issue Jan 8, 2020
On windows, the standard root normalization use UNC which
isn't understood by most programs. Related to #78
@Canop
Copy link
Owner

Canop commented Jan 8, 2020

note: the referenced commit isn't on master right now (it's in a "no-unce" branch)

@stinos
Copy link

stinos commented Jan 9, 2020

I'd be happy to help testing/adding docs. But I can't get started: I defined the br function but still when launching it all I get is

Broot should be launched using a shell function (see https://github.com/Canop/broot for explanations).
The function is either missing, old or badly installed.
Can I install it now? [Y n]

Removing C:\Users\<user>\AppData\Roaming\dystroy\broot\data\launcher\bash\1.
Writing br shell function in C:\Users\<user>\AppData\Roaming\dystroy\broot\data\launcher\bash\1.
Removing C:\Users\<user>\AppData\Roaming\dystroy\broot\config\launcher\bash\br.
Creating link from C:\Users\<user>\AppData\Roaming\dystroy\broot\config\launcher\bash\br to C:\Users\<user>\AppData\Roaming\dystroy\broot\data\launcher\bash\1.

I found neither .bashrc nor .zshrc.
If you're using bash or zsh, then installation isn't complete:
the br function initialization script won't be sourced unless you source it yourself.

You cannot call a method on a null-valued expression.
At C:\Users\<user>\Documents\WindowsPowerShell\PowerShell_profile_curhost.ps1:31 char:5
+     Invoke-Expression $CommandToExecute.Replace('\\?\', '')
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

(that last error is from the br function, I assume broot didn't return non-zero exit code making the function continue)

Any hints?

@Canop
Copy link
Owner

Canop commented Jan 9, 2020

@stinos I just published a new version fixing the 'n' answer being ignored (a problem I discovered yesterday).

@stinos
Copy link

stinos commented Jan 9, 2020

Can confirm that works. Just get a black screen upon launching though, @71 did you do anything special to get this working? If I get some time I'll install a Rust environment for building from source.

@lubieowoce
Copy link

lubieowoce commented Jan 9, 2020

@71 on my system your function crashes if broot doesn't emit a cd command, i.e the temp file is empty -- invoke-expression seems to dislike empty strings. i'm pretty new to PS, but adding a if ($command) { ... } seems to work:

function br {
    $outcmd = new-temporaryfile
    broot.exe --outcmd $outcmd $args
    if (!$?) {
        remove-item -force $outcmd
        return $lastexitcode
    }

    $command = get-content $outcmd
    if ($command) {
        # workaround - paths have some garbage at the start
        $command = $command.replace("\\?\", "", 1)
        invoke-expression $command
    }
    remove-item -force $outcmd
} 

(sorry about the renaming, i just really don't like PS's Capitalize-Everything style)

@71
Copy link
Author

71 commented Jan 10, 2020

@stinos I did have to manually create the file %APPDATA%\dystroy\broot\config\launcher\installed-v1.

@lubieowoce Arh I forgot PowerShell likes to implicitly convert everything... Good catch!

@stinos
Copy link

stinos commented Jan 13, 2020

I did have to manually create the file ...

@71 I already got the file refused there since Canop fixed the issue mentioned above, so that isn't the problem. I think it has to do with rendering/esacpe codes (it does react to Esc key for instance i.e. it's like running headless). If I launch broot in in plain cmd or PS I just get a blank screen. If I launch it in cmd running under Conemu though it printes a ton of escape codes e.g. here's an excerpt:

←[68;1H←[K←[68;1H←[48;5;235m←[38;5;252m ←[0m←[48;5;235m←[38;5;252mHit ←[0m←[48;5;235m←[38;5;178mesc←[0m←[48;5;235m←[38;5;252m to go back, ←[0m←[48;5;235m←[38;5;178menter←[0m←[48;5;235m←[38;5;252m to go up, ←[0m←[48;5;235m←[38;5;178m?←[0m←[48;5;235m←[38;5;252m for help, or a few letters to search←[0m←[48;5;235m←[38;5;252m

@Canop this is going off topic, make a new issue for this or reopen e.g. the 'Windws compatibility' one?

@Canop
Copy link
Owner

Canop commented Jan 13, 2020

I don't want to reopen a too wide issue. I'd like clear separate issues, with reproduction steps and description of the problems, so that they can be addressed.

@lubieowoce
Copy link

lubieowoce commented Jan 13, 2020

how about a separate issue for powershell support? that does seem kind of off-topic here, and it'd be easier to find for people looking for a suitable br function

@stinos
Copy link

stinos commented Jan 14, 2020

An error will be shown, indicating that the path \?\A:\Foo does not exist (even though A:\Foo does exist).

Which PS version? I cannot reproduce this, i.e. running Windows 10 version 1803 with PSVersion 5.1.17134.590 the command cd \\?\A:\Foo works, though leads to cd'ing to Microsoft.PowerShell.Core\FileSystem::\\?\A:\Foo. Don't know when this changed exactly but since a while Windows has extended support for paths like this, e.g. when broot runs $EDITOR \\?\A:\myfile.txt that also works for me.

@71
Copy link
Author

71 commented Jan 16, 2020

@stinos I'm on PS Core (v6.2.2, Windows 10 version 1903), which is a little less Windows-focused than regular PowerShell. cd \\?\A:\Foo doesn't work, cd A:\Foo does. Maybe there's a setting somewhere else...

@Canop Canop added the windows Windows specific problem label Jun 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
windows Windows specific problem
4 participants