Directory.SetCurrentDirectory throws PathTooLongException - c#

There are several related questions on stackoverflow but either my situation is different or I am too dumb to relate those to situation. I am hoping someone can help me with this. Further I am not even much of a .NET developer so I apologize in advance for any wrong terminology use.
My scenario is as follows: The tool that is used to deploy our .net application (One Click?) puts it in a directory whose full name exceeds 300 characters. The application uses a third party component -- lets call it dbstore -- that processes the specified file that resides in the application deployment directory.
So far we were using Assembly.GetExecutingAssembly().GetName().CodeBase to construct the fully qualified name of the file to pass to dbstore. But dbstore uses old style APIs and fails when it tries to open the file.
Since dbstore is not expected to change soon, it was recommended that the application chdir to the deployment directory and pass a relative path name in current directory to it. This is also the approach described in the accepted response PathTooLongException in C# code
However I find that Directory.SetCurrentDirectory also throws PathTooLongException. This happens even when I am using UNC path name, e.g a name starting with \\?\0000000000000\...
Am I doing something fundamentally wrong? Is there another function to use?
EDIT: It seems there is no way to achieve what I am looking for. Far as I can tell there is no way to set current directory to a long path.

Do you get a similar result when using Environment.SetCurrentDirectory() ?
If so, you may want to change your directory subfolder after subfolder.
EDIT:
Windows actually sets a limitation of 255 chars for a file path (WinXP) or 260 chars (Vista).
Note that this limitation does not apply for the filesystem, so you can have a file stored in such a long directory path, but Windows Explorer and many Windows services cannot read from such path.
Actually it seems to also include .NET framework methods since you cannot access such files. You may need to write your own filesystem API, but that's a bit too much overhead. Can't you just shorten the file path ? Does Windows offer a shortened way to address a file (like 8 octet file names) ?
Source: http://labnol.blogspot.com/2006/10/limitations-with-long-file-names-on.html

Related

Deleting long path too long folder from Network Share

I'm trying to delete folders in a shared location on a network using C#. Some of the folder paths are too long for Windows to handle. I've tried multiple options for this. The best one I found was creating a FileSystemObject, adding \\?\ to the path and calling DeleteFolder on the path that I want to delete, which works on my local computer for paths that are too long, because I have mapped drives like C: and G: etc, but when I try to use it on a Network share folder I get either a HRESULT: 0x800A004C (CTL_E_PATHNOTFOUND) or value does not fall within the expected range.
The following is my code:
private static void DeletePathWithLongFileNames(string path)
{
string tmpPath = #"\\?\" + path;
FileSystemObject fso = new FileSystemObject();
fso.DeleteFolder(tmpPath, true);
}
let's say for example, the network + share folder is \\myServer\mySharedFolder\folder1\etc\etc, which would be the path string I'm sending to my delete function
then the tmpPath is showing as "\\\\?\\\\\\myServer\\mySharedFolder\\folder1\\etc\\etc"
I don't know much about UNC so I don't know if this is what is wrong or not. I'm pretty sure there is something wrong with my tmpPath variable, but again I'm not sure. Maybe it's a syntax error But I can't for the life of me figure out what is wrong. Thanks in advance for the help
EDIT: I believe I have found the answer, I am testing it right now. So far it has worked for me. if I run the DeleteFolder method on the following path \\?\UNC\server\sharedFolder\folder1\etc\etc" this seems to work. Now I just have to figure out how to get rid of all those extra slashes.
EDIT 2: This does work, tested it on a Share folder on a network. It just came down to me not understanding UNC paths.
The safe way to delete paths that are too long is to use AlphaFS. AlphaFS is a .NET library providing more complete Win32 file system functionality to the .NET platform than the standard System.IO classes. The most notable deficiency of the standard .NET System.IO is the lack of support of advanced NTFS features, most notably extended length path support (eg. file/directory paths longer than 260 characters).
See Directory Delete: http://alphafs.alphaleonis.com/doc/2.2/api/html/BE179564.htm
Alphaleonis.Win32.Filesystem.Directory.Delete(path)

How to convert DOS path to normal path (.net)

I have a program that tracks changes on a local folder using a FileSystemWatcher object.
The issue is that sometimes, on some environments and situations (I do not know which ones), this watcher gives me an event on a DOS path ("/Hello/How/Are/You" becomes something like "/HE~1/HO~1/AR~1/YO~1").
What I am looking for is a way to force this path back into its full and normal aspect.
Or at least something that can tell me that the path is indeed a DOS path, so I can process the entry differently.
EDIT: it has to work on long paths (+260 chars), so Path.GetFullPath(sShortPath) does not work for me here!
Path.GetFullPath(#"/HE~1/HO~1/AR~1/YO~1") should do what you need.
The best method depends what you are looking for, if you just want to access the file once then the 8byte file names will work for internal file references
if you want to display to the user or store then there are 2 option
Path contains most of the tools you need to manipulate paths
fullPath = Path.GetFullPath(path1);
FileInfo and DirectoryInfo these 2 classes provide persistent access to files and directory information and while they can be created with any valid path both have a Full name property that provides access to the full path
As others said, Path.GetFullPath(sShortPath) works fine if not used on very long paths (+260 chars).
Here is a link I followed that worked for me.
GetLongPathName from kernel32.dll worked fine with me, I just had to change the 255 StringBuilder limit to a higher value to make it work with long paths.

Is it possible to avoid MAX_PATH limit using WiX variables?

I'm developing a project in WinForms, and I'm on the process of creating an installer using WiX.
But when the installer is going to copy a .dll that comes from a really long path, Visual Studio says this:
'Really long route'\EnterpriseLibrary....\ is too long, the fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
I found articles that talks about MAX_PATH limitations like said in this StackOverflow question related with the Windows API.
I'm working on a big team, and we just discovered this known error, but we are not allowed to shorten or modify the path.
I tried the solution that the link above says, using the \\?\ characters before, so my WixVariables remain like this:
<?define examplesPath="\\?\$(sys.CURRENTDIR)\..\..\ExamplesFolder" ?>
That results to be something like this:
\\?\C:\reallylongpath\files
But it doesn't seem to work for WiX variables.
So my question is:
Is there any way to avoid this 260 characters limitation? If so, how?
Please, I need an answer on this!
EDIT: While I try #Jans' suggestion, I also found that, if I add the \\?\ string to my WiX variable, the error message changes. Now it says:
The system cannot find the file '\\?\Reallylongpath\..\..\andreallylongfile\'
I'm thinking that maybe the \\?\ is not converting the ..\ that I need to use... Any suggestion here?
EDIT2: I found this line at msdn:
A consequence is that \\?\ turns off file name normalization performed by Windows APIs, including removing trailing spaces, expanding ‘.’ and ‘..’
:___(
This is a terrible hack, but you could create a symlink to the real directory. A symlink is like a regular link, except for that it behaves exactly like a real directory.
Suppose you have a really long directory that causes you trouble:
C:\blahblahblah\thisisreallylong\andnotaccessible\blahblahblah\
You can create a symlink to it, that has any name you like, but is considerably shorter. Think of it as an alias. So if you call this on your console, for example in the C:\temp directory:
C:\temp\>mklink /D reallylong C:\blahblahblah\thisisreallylong\andnotaccessible\blahblahblah\
then afterwards, you can access C:\temp\reallylong as if it were your real directory. Note that you need local admin rights to create symlinks.

Strange behavior from .NET regarding file paths

I couldn't find any information on this through professor Google, so here I am. Take the given path name and paste it into Windows Explorer. I stumbled across this after discovering bug in my code that generated the paths with an extra '.' in the path name before a directory \ separator...
#"C:\\pathto.\file.ext"
In code, .NET will accept the path when calling File.Create and a file will be generated, but at this path:
#"C:\\pathto\file.ext"
Copying C:\\pathto.\file.ext into Windows Explorer's address bar and watch the '.' disappear and take you to C:\\pathto\file.ext
Is it normal behavior for .NET and Windows to It's not causing an issue because the '.' is being removed by both .NET and Windows when passed into file operations. The real issue is that all the files in the DB have filenames with a '.\', but exists in paths that do not have a '.\'... and File.Exists() works too, although the path is not the 'real' physical location...
What's going on here?
This is a "feature" of the Windows file system. MSDN:
Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".
All normal Windows APIs ignore/remove trailing dots in the file/folder names when regular path is passed in.
If you really need support for trailing dot you need to use "\\?\" prefixed paths and interop all calls yourself (as .Net does not support this file format). See MSDN: Naming Files, Paths, and Namespaces, How to delete a folder that name ended with a dot (".")? and You cannot delete a file or a folder on an NTFS file system volume for more info.
Here is related question showing how to PInvoke function that accepts long file path: c# call Win32 API for long file paths?

How to know the next temp file to be created in windows?

I am by no means a programmer but currently am wondering if an application creates a temp file that windows names. For example the file it creates is tmp001, is there a way i can take that name tmp001 and ask windows to give me the next temp file it would create before it creates it.
Thanks,
Mike
There is no direct means to get to know the next temporary filename to be created.
For example, programmers use the System.IO.Path.GetTempFileName method, but one can add application-specific prefixes or suffixes in order to make it easier for the application to find its newly created files.
One can even choose to save this temporary file elsewhere than the system Temp folder.
You would need to define a "temp file" much more explicitly in order to answer this question with a "Yes". The problem is that a "temp file" is just something not meant to be kept. It could exist anywhere on the system and be created by a user, application, or service. This would make it nearly (or actually) impossible to answer your question with a "Yes".
If you constrain the definition of a temp file to just the files in the official temp folder (or a subfolder), you still have a problem if you're trying to catch names not generated by windows. Any app could produce a particularly named temp file in that folder, without Windows caring.
If you further constrain the definition to be only those files named by Windows, you might be able to get somewhere. But, does that really meet your needs?
After all of that, maybe it would be better to describe the problem you're trying to solve. There may be a much better (workable) solution that would address the issue.
Typically applications use the Win32 API GetTempFileName to get the temporary directory.
The process of how the temp file is generated is described there.
I'm not sure why you want this info, but perhaps you could for example register for directory changes via a Win32 API like ReadDirectoryChangesW or by using a mini filter driver.
This kind of code just cannot work reliably on a multi-tasking operating system. Another thread in another process might pre-empt yours and claim the file name you are hoping to create.
This is otherwise easy enough to work around, just name your own files instead of relying on Windows doing it for you. Do so in the AppData folder so you'll minimize the risk of another process messing it up.

Categories