When I recursive through some folders and files, I encounter this error:
The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directoryname must be less than 248 characters.
Here's my function
private void ProcessDirectory(DirectoryInfo di)
{
try
{
DirectoryInfo[] diArr = di.GetDirectories();
foreach (DirectoryInfo directoryInfo in diArr)
{
if (StopCheck)
return;
ProcessDirectory(directoryInfo);
}
ProcessFile(di);
}
catch (Exception e)
{
listBoxError.Items.Add(e.Message);
}
TextBoxCurrentFolder.Text = di.ToString();
}
I cannot make the directory names shorter, because I'm not allowed too so... How can I solve this problem?
Added:
Here's the other function:
private void ProcessFile(DirectoryInfo di)
{
try
{
FileInfo[] fileInfo = di.GetFiles();
if (fileInfo.LongLength != 0)
{
foreach (FileInfo info in fileInfo)
{
Size += info.Length;
CountFile++;
}
}
}
catch (Exception e)
{
listBoxError.Items.Add(e.Message);
}
}
EDIT
Found this where he used Zeta Long Paths:
How can I use FileInfo class, avoiding PathTooLongException?
Have implemented it and now i'm going to let the program run over the night to see if it works.
EDIT
Used the ZetaLongPath yesterday and it worked great! It even went through folders that needed permission access.
EDIT
Instead of zetalongPath, I've used Delimon.Win32.IO.dll which i think is much better. It has the same interfaces as Win32.
Here's more info about the Delimon library referred to earlier. Its a .NET Framework 4 based library on Microsoft TechNet for overcoming the long filenames problem:
Delimon.Win32.IO Library (V4.0).
It has its own versions of key methods from System.IO. For example, you would replace:
System.IO.Directory.GetFiles
with
Delimon.Win32.IO.Directory.GetFiles
which will let you handle long files and folders.
From the website:
Delimon.Win32.IO replaces basic file functions of System.IO and
supports File & Folder names up to up to 32,767 Characters.
This Library is written on .NET Framework 4.0 and can be used either
on x86 & x64 systems. The File & Folder limitations of the standard
System.IO namespace can work with files that have 260 characters in a
filename and 240 characters in a folder name (MAX_PATH is usually
configured as 260 characters). Typically you run into the
System.IO.PathTooLongException Error with the Standard .NET Library.
This is a known limitation in Windows: http://msdn.microsoft.com/en-us/library/aa365247.aspx
I don't believe you'll be able to get around it, so whoever is telling you that you aren't allowed to make them shorter, you'll have a pretty solid argument as to why you have to.
The only real alternative is to move the deep folder somewhere else, maybe right at the root of your drive.
EDIT: Actually there may be a workaround: http://www.codinghorror.com/blog/2006/11/filesystem-paths-how-long-is-too-long.html
You'll have to use P/Invoke and the Unicode version of the Win32 API functions. You'll need FindFirstFile, FindNextFile and FindClose functions.
Also see:
C# deleting a folder that has long paths
DirectoryInfo, FileInfo and very long path
You can use the subst command. It creates a virtual drive starting at whatever folder you pass as parameter.
For example, you can turn the path c:\aaaaaaaaaaaaaaaaaaaaaa\aaaaaaaaaaaaaaaaaaaa\aaaaaaaaaaaaaa into the drive R: and continue exploring the subfolders of c:\aaaaaaaaaaaaaaaaaaaaaa\aaaaaaaaaaaaaaaaaaaa\aaaaaaaaaaaaaa thru R:...
Do you know what I mean?
I also recommend reading this three-part blog post from the BCL Team, published in 2007, but relating specifically to the limitations of DirectoryInfo when it comes to deeply nested folders. It covers the history of the MAX_PATH limitation, the newer \?\ path format, and various .NET-based solutions and workarounds.
Comprehensive, though perhaps a bit dated.
Related
I have been problem to solve an appointment of Veracode Scanner in my project. I created a function to validate a file but it did not pass in veracode scanner;
Here is the code of my function:
public static string GetSafeFileName(string fileNameToValidate)
{
fileNameToValidate= fileNameToValidate.Replace("'", "''").Replace(#"../", "").Replace(#"..\", "");
char[] blackListChars = System.IO.Path.GetInvalidPathChars();
char[] blackListFilename = System.IO.Path.GetInvalidFileNameChars();
foreach (var invalidChar in blackListChars)
{
if (fileNameToValidate.Contains(invalidChar))
{
fileNameToValidate = fileNameToValidate.Replace(invalidChar, ' ').Trim();
}
}
string fullPath = Path.GetFullPath(fileNameToValidate);
string directoryName = Path.GetDirectoryName(fullPath);
string fileName = Path.GetFileName(fullPath);
foreach (var invalidChar in blackListFilename)
{
if (fileName.Contains(invalidChar))
{
fileName = fileName.Replace(invalidChar, ' ').Trim();
}
}
string finalPath = Path.Combine(directoryName, fileName);
return finalPath;
}
What are the changes i have to fix the cwe 73 appointment in Veracode scanner? Anybody can help me?
My project is a windows forms running on .net 4.0
Thanks,
Bruno
Your problem is that Veracode doesn't actually detect what your code is doing, it detects what cleanser function is (or is not) being called. If you login to Veracode and search for help on "Supported Cleansing Functions" you'll find the list that are detected in your language.
Unfortunately, the list for .Net doesn't include anything for a CWE-73.
So, your solution is to specifically label your function as a cleanser for CWE-73 using a custom cleanser annotation. Search Veracode help for "Annotating Custom Cleansers".
using Veracode.Attributes;
[FilePathCleanser]
public static string GetSafeFileName(string fileNameToValidate)
{
...
That said, your implementation is not secure. Try passing in "C:\Windows\System32\notepad.exe" as a filename to be written to and you'll see the problem.
Blacklisting can only deal with what you expect. Whitelisting is a much stronger approach. Your approach should be based on a whitelist of directories, a whitelist of characters for filenames, and a whitelist of file extensions.
I have tried to solve similar problem but in java context. We used ESAPI as external library. You can review esapi project (for ideas how to realise a better solution in your project):https://github.com/ESAPI/esapi-java-legacy
Actually using esapi validator didn't solve the problem with veracode, but in my opinion reduce the risk for attack. With such a library you can enshure that user can't read file out of parent folder(you must hardcode such a directory) and that the user can't read a file with unproper extension -> you can add such a list with file extensions. But this library cant garantee that you can't manipulate files in the parent directory with allowed extensions.
So if you think that all needed verifications of filepaths are done you must ask for mitigation by design or develope a Map with all needed file resources in the project to enshure that there is no way the user to manipulate external files.
Also if you think that you have created a good filepath verification you can use cleanser annotation to mark your method. Here you can read more about custom cleansers
https://help.veracode.com/reader/DGHxSJy3Gn3gtuSIN2jkRQ/xrEjru~XmUHpO6~0FSae2Q
I am using Directory.GetDirectories() with a Linq statement to loop through all directories in a folder that aren't system folders, however I am discovering a bunch of bad ReparsePoints in the folder, which is causing the method to take a long time as it times out on each bad reparse point.
The code I am currently using looks like this:
subdirectories = directory.GetDirectories("*", SearchOption.TopDirectoryOnly)
.Where(d => ((d.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)
&& ((d.Attributes & FileAttributes.System) != FileAttributes.System));
I have also tried using code like this for testing, but it also hangs for a full minute or so on the bad folders:
foreach (var item in dir.GetDirectories("*", SearchOption.TopDirectoryOnly))
{
Console.WriteLine(item.Name);
Console.WriteLine(item.Attributes);
}
It should be noted that the above bit of code works fine in .Net 4.0, but in 3.5 it will hang for a minute on each bad reparse point.
Trying to open these folders manually in Windows Explorer results in a "Network Path Not Found" error.
Is there another way to loop through good subfolders inside a folder that doesn't use the Attributes property, or that bypasses the bad reparse points?
I have already tried using Directory.Exists(), and that is equally slow.
According to this answer: *FASTEST* directory listing
For the best performance, it is possible to P/Invoke NtQueryDirectoryFile, documented as ZwQueryDirectoryFile
From MSDN: FILE_REPARSE_POINT_INFORMATION structure
This information can be queried in either of the following ways:
Call ZwQueryDirectoryFile, passing FileReparsePointInformation as the value of FileInformationClass and passing a caller-allocated, FILE_REPARSE_POINT_INFORMATION-structured buffer as the value of FileInformation.
Create an IRP with major function code IRP_MJ_DIRECTORY_CONTROL and minor function code IRP_MN_QUERY_DIRECTORY.
I have to save images to a folder located in "c:\inetpub\wwwroot\" and named as "UploadedImages". Here is my code:
public string SaveImage(string base64,int compno)
{
string res = "";
try
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64)))
{
using (Bitmap bm2 = new Bitmap(ms))
{
bm2.Save(Server.MapPath("~/UploadedImages/ID"+compno+".jpg"));
}
}
res = "done";
}
catch (Exception ex) {
res = ex.ToString();
}
return res;
}
but it throws "A generic error occured in GDI+ at System.Drawing.Image.Save" exception. What am I doing wrong? This code works fine when saving image locally as
bm2.Save("D:Embasy\UploadedImages\ID"+compno+".jpg"));
What changes do I need to make to save images in localhost directory?
Your not going to believe this -- the site running v1.1 had a virtual directory set-up which was mapped to the directory in which the image was saved to -- things worked fine.
The v2.0 site also had the same virtual directory name, but the physical path was different -- I changed the path to point to the same directory as the v1.0 site and now the code works.
So in short -- you were right about the "path must exist".
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
and kindly refer this link
http://msdn.microsoft.com/en-us/library/xs6ftd89.aspx
When you are using Server.Mappath
bm2.Save(Server.MapPath("~/UploadedImages/ID"+compno+".jpg"));
"~(tield)" : is point to project/application root folder c:\inetpub\wwwroot\yourproject
then find remaining your path /UploadedImages and then create ID1.jpg.
But your imagefolder "UploadImages" is exist in d: not in c:\inetpub\wwwroot\yourproject
if you want to exist your image folder in D: then you should to create
virtual directory and then you need to apply path as relevant
My problem actually was that every time i published website, I replaced the "UploadedImages" folder too and thus permissions were changed. So, i didnt replaced the folder again after changing its permissions and creating "everyone" group and giving full rights to it. Now code is working perfectly :)
I want to get the path and version number of a ClickOnce application, provided the name of the ClickOnce application.
When I manually searched for it, I found it at the path as follows:
'C:\Users\krishnaim\AppData\Local\Apps\2.0\1HCG3KL0.K41\VO5BM4JR.RPO\head..tion_7446cb71d1187222_0005.0037_37dfcf0728461a82\HeadCount.exe'
But this keeps on changing, and it will become a hard-coded path. Is there another way to get a ClickOnce application (for example, HeadCount.exe which is already installed) path and version number using C#/.NET code?
It seems a little bizarre, but getting the current directory of the executing assembly is a bit tricky so my code below may be doing more than you think it should, but I assure you it is mitigating some issues where others may attempt to use Assembly.GetExecutingAssembly.Location property.
static public string AssemblyDirectory
{
get
{
//Don't use Assembly.GetExecutingAssembly().Location, instead use the CodeBase property
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return System.IO.Path.GetDirectoryName(path);
}
}
static public string AssemblyVersion
{
get
{
var asm = Assembly.GetExecutingAssembly();
//If you want the full four-part version number:
return asm.GetName().Version.ToString(4);
//You can reference asm.GetName().Version to get Major, Minor, MajorRevision, MinorRevision
//components individually and do with them as you please.
}
}
In order to do a ClickOnce application update you do not have to do so manually as long as you are using the standard deployment manifests (which I don't know how to ClickOnce unless you do use them).
The MSDN article Choosing a ClickOnce Update Strategy describes the different options for application updates.
I use VS 2008, .net 3.5, C# projects. I need do the same functionally like Microsoft.VisualBasic.FileIO.FileSystem.DeleteDirectory.
Anyone says referencing the Microsoft.VisualBasic is often undesirable from within C#. Any association with VB from within C# code strikes me as undesirable.
Using FileSystem class, this is a perfectly fine solution, but I prefer not references Microsoft.VisualBasic library. That one I would avoid.
private static void DeleteDirectory(string destino)
{
//UIOption Enumeration. Specifies whether to visually track the operation's progress. Default is UIOption.OnlyErrorDialogs. Required.
//RecycleOption Enumeration. Specifies whether or not the deleted file should be sent to the Recycle Bin. Default is RecycleOption.DeletePermanently.
//UICancelOption Enumeration. Specifies whether to throw an exception if the user clicks Cancel. Required.
Microsoft.VisualBasic.FileIO.FileSystem.DeleteDirectory(destino,
Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
Microsoft.VisualBasic.FileIO.RecycleOption.DeletePermanently,
Microsoft.VisualBasic.FileIO.UICancelOption.ThrowException);
//Directory.Delete(destino, true);
}
Other samples:
How do you place a file in recycle bin instead of delete?
Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(file.FullName,
Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
Microsoft.VisualBasic.FileIO.RecycleOption.SendToRecycleBin);
Possible duplicate of
System.IO Versus VisualBasic.FileIO
You can use FileIO from Microsoft.VisualBasic and AFAIK it will not behave unreasonably..
The same/similar functionality is available within the System.IO namespace:
System.IO.FileInfo fi = new System.IO.FileInfo("C:\\Test.txt");
fi.Delete();
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo("C:\\Test");
di.Delete(true); //Recursive, pass false for no recursion.
I'm not aware of existing SendToRecycleBin equivalent, but you could try:
di.MoveTo("C:\\$Recycle.Bin\\S-..."); //You'd need to know the SID of the user logged in
To replicate the example
The following code will give you something similar to what you have provided as your example:
try
{
bool deletePermanently = true; //Set to false to move
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo("C:\\Test");
if (deletePermanently)
{
if (di.Exists)
di.Delete(true);
}
else
{
if (di.Exists)
di.MoveTo("C:\\$Recycle.Bin\\S-0-0-00-00000000-000000000-0000000000-000"); //Replace with your SID
}
}
catch
{
Console.WriteLine("Error deleting directory"); //Add exception detail messages...
}
Again, the above example would need you to identify the SID of the user before being able to send to the recycle bin.
You could try the following.
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo("C:\\MyDirectoryToDelete");
di.Delete(true);
Or even
System.IO.Directory.Delete("Path goes here");
Hope this helps.