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: render of folder cointaining OneDrive folder fails on Windows #535

Open
3 tasks done
kmoschcau opened this issue Dec 11, 2024 · 15 comments
Open
3 tasks done

bug: render of folder cointaining OneDrive folder fails on Windows #535

kmoschcau opened this issue Dec 11, 2024 · 15 comments
Labels
bug Something isn't working help wanted Extra attention is needed P2 Not a priority. PRs welcome

Comments

@kmoschcau
Copy link

Did you check the docs and existing issues?

  • I have read the docs
  • I have searched the existing issues

Neovim version (nvim -v)

v0.11.0-dev-1335+g3f1d09bc94

Operating system/version

Windows 11 Enterprise 23H2 22631.4602

Describe the bug

In my home folder on Windows on my work machine, there's a OneDrive folder that causes oil to fail to render my home folder. I get this error notification:

Error rendering oil buffer oil:///C/Users/KaiMoschcau/: EINVAL: invalid argument: C:\Users\KaiMoschcau\\OneDrive - blecon GmbH

I have no idea what makes this folder special enough to fail. The folder properties don't look special to me and yazi is able to render my home folder no problem. I can also explore inside that OneDrive folder with oil without problems. This really only occurs when trying to render the OneDrive folder.

Also when I navigate to my Windows home folder from inside my WSL instance, oil is able to render my home folder without problems as well.

What is the severity of this bug?

tolerable (can work around it)

Steps To Reproduce

  1. Have a OneDrive setup in your Windows home folder
  2. Navigate to your home folder with oil
  3. The buffer just shows Error: EINVAL: invalid argument: C:\Users\KaiMoschcau\\OneDrive - blecon GmbH

Expected Behavior

Oil should render the buffer as normal and allow me to move through my home folder.

Directory structure

Here's some yazi output of the folder structure for context. The folder OneDrive - blecon GmbH in the middle column is the selected one.

~
  󰉋 KaiMosc│  Lokale Einstellungen -> C:\Users\KaiMoschca │ 󰉋 Anlagen
   Public │  Music                                       │ 󰉋 Apps
           │  Netzwerkumgebung -> C:\Users\KaiMoschcau\Ap │ 󰉋 Bilder
           │ 󰉋 onecoremsvsmon                              │  Desktop
           │ 󰉋 OneDrive                                    │ 󰉋 Dokumente
           │ 󰉋 OneDrive - blecon GmbH                      │ 󰉋 Microsoft Teams Chat Files
           │ 󰉋 OWASP ZAP                                   │  Videos
           │  Recent -> C:\Users\KaiMoschcau\AppData\Roam │ 󰈔 Kai @ blecon GmbH.url
           │ 󰉋 Saved Games                                 │
[…]

Repro

-- save as repro.lua
-- run with nvim -u repro.lua
-- DO NOT change the paths
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "runtime", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "--single-branch",
    "https://github.com/folke/lazy.nvim.git",
    lazypath,
  })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  {
        "stevearc/oil.nvim",
        config = function()
            require("oil").setup({
              -- add any needed settings here
            })
        end,
  },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

Did you check the bug with a clean config?

  • I have confirmed that the bug reproduces with nvim -u repro.lua using the repro.lua file above.
@kmoschcau kmoschcau added the bug Something isn't working label Dec 11, 2024
@stevearc
Copy link
Owner

Unfortunately I have neither OneDrive nor a Windows computer right now. I won't be able to help debug this.

@stevearc stevearc added help wanted Extra attention is needed P2 Not a priority. PRs welcome labels Dec 21, 2024
@kmoschcau
Copy link
Author

Alright. I did some more digging and found out the following:

  • The directory in question shows up with Mode lar-- in PowerShell's Get-ChildItem output
  • l stands for ReparsePoint (which could also be symbolic links, but I don't think that's the case here)
  • Apparently Windows uses "File System Filters" to read the data in the Reparse Point in order to display the file

@stevearc
Copy link
Owner

Interesting, so it seems like the issue is that we can't list a directory that is a reparse point? I don't know if those would show up as type "link" or as a normal directory, but perhaps the error happens when we're trying to read the link data.

@skt041959
Copy link

I also have this issue. I don't think it's related with the ReparsePoint as my other symbol link files shown correctly.

There is also another error reported when this issue occurs like

E5107: Error loading lua [string ":lua"]:1: invalid escape sequence near ''C:'

I think the problem happens when some code dealing with path like C:\Users\...

@kmoschcau
Copy link
Author

I also have this issue. I don't think it's related with the ReparsePoint as my other symbol link files shown correctly.

Not all ReparsePoints are symbolic links from what I understand of the Microsoft docs. But every symbolic link is a ReparsePoint. ReparsePoint is just arbitrary data, that need specific "file system filters" to read. So whatever OneDrive does with that folder, is implemented using ReparsePoint data and a file system filter. To additionally counter your point: simple symbolic links do not cause issues for me either.

There is also another error reported when this issue occurs like

E5107: Error loading lua [string ":lua"]:1: invalid escape sequence near ''C:'

I think the problem happens when some code dealing with path like C:\Users\...

I can't confirm this. I've been using Oil in neovim on a Windows machine for well over a year now and never ran into this problem.

@kmoschcau
Copy link
Author

Interesting, so it seems like the issue is that we can't list a directory that is a reparse point? I don't know if those would show up as type "link" or as a normal directory, but perhaps the error happens when we're trying to read the link data.

I think I understand this a bit better now from looking in the docs again. There is no such thing as a file being a Reparse Point. It's more like that the file has a Reparse Point. And the Reparse Point is data specific to a File System Filter, plus an identifier which File System Filter to use. So likely whatever oil is using on Windows to "stat" the file, needs to be told to use the appropriate File System Filter. That same "stat" is likely what is throwing the EINVAL error.

@skt041959
Copy link

I have debugged oil with one-small-step-for-vimkind, and located the issue. The error is indeed reported by uv.fs_readlink. Then the error handling callback function interrupted the buffer rendering and only leave the error reporting.

It should be better to render the rest entries in path, and mark the bad entry.

image

@skt041959
Copy link

FYI, libuv seems has lots of issue regarding OneDrive on windows libuv/libuv#2348

@stevearc
Copy link
Owner

stevearc commented Jan 8, 2025

So fs_readlink is returning an error when called on that folder. In the yazi example, it appears to display the folder as a normal folder, not a link, but we only call fs_readlink when the entry type is link. Is it possible to figure out what's going on here? Why is the type link if it can't be read by fs_readlink? Is this some sort of weird special case link that exists on Windows? Is there any way to detect this situation from the stat or other information?

@skt041959
Copy link

@stevearc I have tried use uv.fs_lstat to double check the type of OneDrive folder and return false. Would you please help add the implementation to prevent the invalid readlink call ? I can't figure out a patch, because the callback chain is too complicated to me.

@kmoschcau
Copy link
Author

In the yazi example, it appears to display the folder as a normal folder, not a link, but we only call fs_readlink when the entry type is link. Is it possible to figure out what's going on here? Why is the type link if it can't be read by fs_readlink? Is this some sort of weird special case link that exists on Windows? Is there any way to detect this situation from the stat or other information?

I think that comes back to what I found out earlier. Every symlink on Windows is also a Reparse Point, but not every Reparse Point is a symlink. It might be that your check is too wide.

@stevearc
Copy link
Owner

stevearc commented Jan 8, 2025

I have tried use uv.fs_lstat to double check the type of OneDrive folder and return false. Would you please help add the implementation to prevent the invalid readlink call ?

The change we want to make is probably going to live here

if entry[FIELD_TYPE] == "link" then
read_link_data(entry_path, function(link_err, link, link_stat)
if link_err then
return cb(link_err)
end
meta.link = link
if link_stat then
-- Use the fstat of the linked file as the stat for the link
meta.link_stat = link_stat
meta.stat = link_stat
elseif require_stat then
-- The link is broken, so let's use the stat of the link itself
uv.fs_lstat(entry_path, function(stat_err, stat)
if stat_err then
return cb(stat_err)
end
meta.stat = stat
cb()
end)
return
end
cb()
end)
elseif require_stat then

But how we want to do it depends on what information we can get. Did you find a way to detect this kind of link-that-will-fail-readlink ahead of time, or are we going to have to handle the error?

I think that comes back to what I found out earlier. Every symlink on Windows is also a Reparse Point, but not every Reparse Point is a symlink. It might be that your check is too wide.

Our check is just "does the fs_readdir call return a type = link". I think that it's reasonable to expect that if the type is "link" that a call to fs_readlink will not error. Maybe this is a bug in libuv, or maybe this is some weird Windows issue, but we have at least some reason to believe that we're dealing with an actual link here.

@skt041959
Copy link

In my testing, when fs_readdir return the entry as type=="link", I use fs_lstat to check again and the type is not link.
So, I think we can prevent the invalid call by double checking the type using fs_lstat.

@skt041959
Copy link

skt041959 commented Jan 9, 2025

Maybe this is a bug in libuv, or maybe this is some weird Windows issue

But, when I test with nodejs which is actually also using libuv to operate filesystem, its fs.readdir didn't treat the OneDrive folder as link. I think it should be a specific libuv issue of neovim

@kmoschcau
Copy link
Author

You could probably limit the additional check to only run on Windows, if that improves performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed P2 Not a priority. PRs welcome
Projects
None yet
Development

No branches or pull requests

3 participants