malxau / yori

Yori is a CMD replacement shell that supports backquotes, job control, and improves tab completion, file matching, aliases, command history, and more.
http://www.malsmith.net/yori/
MIT License
1.23k stars 30 forks source link

Implement long path pseudo current directory #106

Open RamonUnch opened 1 year ago

RamonUnch commented 1 year ago

I wanted to first thanks you for your amazing work. on this project.

In the WIN32 API we are limited to MAX_PATH for the current directory. Yori for now uses the SetCurrentDirectory() function in its implementation of the YoriLibSetCurrentDirectory() when calling chdir.

So when I try to chdir to a very long path name I get the The filename or extension is too long. error

I was wondering if Yori could instead simulate a pseudo current directory (issuing a warning maybe), so that file manipulation would behave more transparently. When you would call any internal command, Yori would expend the full path name with the \\?\ prefix to the command. This way it would be more convenient to work on a set of files that are nested deeply. As long as the commands you use are long path aware.

Of course all the Yori commands are already long path aware, so it would not require extra work for them.

There would still be a problem when calling an external command because there is no way Yori could know for sure if a parameter is supposed to be a filename. So people will have to Use Ctrl+Tab, but it would be fine in my opinion.

There is also the option to use the short path name if available when path is too long for SetCurrentDirectory(). So people would not have to type the short path manually. This would push up quite a lot the depth at which you can normally work.

Of course you are more qualified than me to determine what the best option would be. I guess using short path name could also lead to other drawbacks.

EDIT: I am using the latest Yori 1.80 release under Windows Server 2003.

malxau commented 1 year ago

That's what cd -e does:

C:\>cd -?
Chdir 1.80
  Build 20221126

Changes the current directory.

CHDIR [-e] [-license] <directory>

   -e             Change to an escaped long path
C:\>cd -e c:\
\\?\C:\>cd c:\
C:\>

As you noted, this has (bad) compatibility consequences. CMD will interpret these current directories as UNC, which means it automatically change directory to \Windows when launched with one of these active. That breaks all .bat and .cmd scripts. This is why Yori uses prefixed long paths internally for almost everything, except for this, and why I didn't want to silently use prefixed long paths in this specific case. As you say, Yori tools should work, although since this isn't the default operation I haven't tested them in a while.

RamonUnch commented 1 year ago

Unfortunately when testing cd -e I still cannot set a long path name as current directory. If the path name is short enough then it works. and I see the nice \\?\ prefix

For example I get after cd -e:

chdir: could not change directory: \\?\D:\12345678\12345678901234567890123456789
01234567890\1234567890123456789012345678901234567890\123456789012345678901234567
8901234567890\1234567890123456789012345678901234567890\1234567890123456789012345
678901234567890\123456789012345678901234567890\123456789012345678901234567890: T
he filename or extension is too long.

Maybe this is because I use Old windows Server 2003? Windows 7 also gets this problem (I just checked).

I was not sure of what the -e parameter meant because indeed it made no difference when trying to chdir in a long path name. Sorry I forgot to mention that. Or maybe you mean something else?

malxau commented 1 year ago

Ouch, you're right, it looks like -e is basically useless.

As far as I can tell:

Currently the only way I could see this working is to temporarily reset current directory before launching a child, launch the child with debugging enabled, and patch the child's memory to contain the correct current directory and buffer lengths. The problem with doing this is it needs to be recursive - when the child wants to launch another child, that needs to be fixed up too, but CreateProcess fails if the current directory isn't restored before it's called, so the debugger would need to intercept calls to CreateProcess to perform the necessary fixups. Note in particular that the child can be launched either with an explicit current directory or inheriting its parent's current directory, so this requires breaking on CreateProcess, inspecting the arguments and parent state, intercepting the return from CreateProcess (to restore parent state) and applying the saved state to the child on its initial break.

In other words, I'm not sure it's worth pursuing :) Yori already has code to be a debugger in certain cases, but this seems like the most invasive case yet.

RamonUnch commented 1 year ago

In other words, I'm not sure it's worth pursuing :) Yori already has code to be a debugger in certain cases, but this seems like the most invasive case yet.

I agree it would be too much trouble. Current directory was always limited even with UNC because it is legacy from unix/dos and NT api only uses absolute paths. So I guess we are mostly out of luck.

Maybe the cd -s switch could be used to use the short path so that when a path is just a bit too long we could still chdir inside. This would be a simple workaround, far from perfect of course. the short path also has the advantage to only have ascii characters and no spaces which is also helpful when invoking non-Unicode and/or non spaces aware programs. I used to use a shortened launcher for several programs that were just stupid.