how to go one step backwards in path in C# - c#

I want to get the path that my application is located in. I get the physical path by following code:
string filePath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
I get something like this as the result:
D:\\Projects\\UI\\IAC.SMS.MvcApp\\
I know that I can sepetare the string by "\" and combine them together. But is there an easy way to go one step back and get this?
D:\\Projects\\UI\\

You're looking for Directory.GetParent method.
var directoryName = Path.GetDirectoryName("D:\\Projects\\UI\\IAC.SMS.MvcApp\\");
var parentName = Directory.GetParent(directoryName).FullName;
Or
var parentName = new DirectoryInfo("D:\\Projects\\UI\\IAC.SMS.MvcApp\\").Parent.FullName;

Directory.GetParent will work in some cases, but it involves a performance penalty due to the creation of a DirectoryInfo object which will be populated with all sorts of information about the directory that may not be needed (e.g. creation time). I'd recommend Path.GetDirectoryName if all you need is the path, especially since with this method the path doesn't have to exist and you don't have to have permission to access it for the call to succeed.
var filePath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
var parent = Path.GetDirectoryName(filePath);

Related

Parsing string containing Special Folder

I've allowed for custom paths to be entered and wanted the default to be something along the lines of:
%UserProfile%/Documents/foo, of course this needs to successfully parse the string and though it will work in Windows Explorer, I was wondering if I'm missing a library call or option for parsing this correctly.
DirectoryInfo's constructor certainly doesn't work, treating %UserProfile% like any other folder name.
If there is no good way, I'll manually parse it to substitute %foo% with the actual special folder location if it is in the Special Folders Enumeration.
Edit:
Code that does what I'm looking for (though would prefer a proper .NET library call):
var path = #"%UserProfile%/Documents/foo";
var specialFolders = Regex.Matches(path, "%(?<possibleSpecial>.+)%");
foreach (var spec in specialFolders.AsEnumerable())
{
if (Enum.TryParse<Environment.SpecialFolder>(spec.Groups["possibleSpecial"].Value, out var sf))
{
path = Regex.Replace(path, spec.Value, Environment.GetFolderPath(sf));
}
}
Use Environment.ExpandEnvironmentVariables on the path before using it.
var pathWithEnv = #"%UserProfile%/Documents/foo";
var path = Environment.ExpandEnvironmentVariables(pathWithEnv);
// your code...

C# Combining two relative network paths

The System.IO.Path Methods gave me some really weird results while combining two paths;
string Dir = "\\server1\\customers\\Test";
string path = "..\\..\\customers\\Test\\hello.pbt";
path = Path.Combine(Dir, path);
// path = "\\server1\\customers\\Test\\..\\..\\customers\\Test\\hello.pbt"
now i want to combine these paths:
path = "\\server1\\customers\\Test\\hello.pbt" // aim
but with the Path.GetFullPath method, it doesnt go backwards to the server as it should
path = Path.GetFullPath(path)
// path = "\\server1\\customers\\customers\\Test\\hello.pbt"
I Already tried all methods in described in Combining two relative paths with C# answers
The issue appears to be that .NET (and maybe Windows) does not view the parent of \\server1\customers to be \\server.
It looks like technically \\server is not a valid UNC path (i.e. you can't store files there directly).
var thisWorks = Directory.GetParent(Dir);
var thisIsNull = Directory.GetParent(Directory.GetParent(Dir).FullName);
Thus when you ask for ..\\..\\ it effectively ignores one of them since it deduces it can't go any higher up the directory tree...

C# winforms get nth folders from path

I've got an absolute path available to me. Say: C:/Program/CoreFiles/Folder1/Folder2/File.txt.
I need to copy that file to C:/Program/Projects/ProjectName/ but it needs to keep Folder1/Folder2/File.txt intact. So the end result should be C:/Program/Projects/ProjectName/Folder1/Folder2/File.txt.
My first attempt at solving this was to try and get the relative path between 2 absolute paths. Found Path.GetRelativePath(string, string) which obviously didn't help as it wasn't meant for WinForms. It would mess up anyway as the final result would be C:/Program/Projects/ProjectName/CoreFiles/Folder1/Folder2/File.txt.
The target directory is empty and I don't know the relative path to copy beforehand other than somehow getting that info out of the absolute path. Since File.Copy won't create folders that don't exist yet, I need to create them first. So how do I get the path that leads up to the file from the CoreFiles directory out of the absolute path?
The only working solution I can come up with is using regex to just replace CoreFiles with Projects/ProjectName in the path string and work with that. But that somehow seems the wrong approach.
Since you can't use Path.GetRelativePath. I suggest looking at another answer that describes how to do this yourself.
Like here...
How to get relative path from absolute path
Using the method in that answer, you can do the rest of your task as shown below.
string sourcePath = "C:/Program/CoreFiles/Folder1/Folder2/File.txt";
string sourceRoot = "C:/Program/CoreFiles/";
string destinationRoot = "C:/Program/Projects/ProjectName/";
// Use built-in .NET Path.GetRelativePath if you can. Otherwise use a custom function. Like here https://stackoverflow.com/a/340454/1812944
string relativePath = MakeRelativePath(sourceRoot, sourcePath);
// Combine the paths, and make the directory separators all the same.
string destinationPath = Path.GetFullPath(Path.Combine(destinationRoot, relativePath));
// Create nested folder structure for your files.
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
// Copy the file over.
File.Copy(sourcePath, destinationPath);

Replace StartInfo.Filename user

I've been googleing for hours without any results.
I'm trying to open up a program that is located in "C:\Users\myUsername\" file, but I cannot find any way to replace MY username to other application-users.
firstProc.StartInfo.FileName = #"C:\Users\Username?\AppData\Roaming\GameWool\Launcher.exe";
firstProc.StartInfo.UseShellExecute = false;
firstProc.StartInfo.RedirectStandardInput = true;
So, I'm basically trying to replace MY \Users\USERNAME. So, if someone is using the application, he's supposed to open the same "game" using their OWN \Users\Username.
I hope you get my point.
You can use System.Environment.UserName, this will retrieve the current username
For some reasons, the path of the user's personnal folders may differs. You can instead use
var UserFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
But since you want to use AppData\Roaming\, this will directly lead you to that folder :
// C:\Users\username\AppData\Roaming
var UserRoamingFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
In your case, for the last example, the path will looks like this :
firstProc.StartInfo.FileName = $#"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\GameWool\Launcher.exe"

Securely enforcing user-input file paths within subdirectories

I know the solid security recommendation of avoiding accepting user input that you then use to choose a path to read/write a file. However, assuming you have a base directory you want to keep within (such as the root of an ftp folder), how do you best ensure that a given user input keeps us within that folder?
For instance,
Path.Combine(_myRootFolder, _myUserInput)
could still take us outside of _myRootFolder. And this could also be dodgy
newPath = Path.Combine(_myRootFolder, _myUserInput)
if (newPath.StartsWith(_myRootFolder))
...
given something like "/back/to/myrootfolder/../../and/out/again" from the user. What are the strategies for this? Am I missing a blindingly obvious .NET method I can use?
Within ASP.NET applications you can use Server.MapPath(filename) which will throw an exception if the path generated goes outside of your application root.
If all you want is a safe file name and you just want all files in there it becomes simpler;
FileInfo file = new FileInfo(
Server.MapPath(
Path.Combine(#"c:\example\mydir", filename)));
If you're outside of ASP.NET like you indicate then you could use Path.GetFullPath.
string potentialPath = Path.Combine(#"c:\myroot\", fileName);
if (Path.GetFullPath(potentialPath) != potentialPath)
// Potential path transversal
Or you call Path.GetFullPath and then check the start of it matches the directory you want locked to.
I know, that this thread is quiet old, but to prevent following readers from writing code with potential security errors, I think I should point out, that using Path.Combine(arg1, arg2) isn't save when arg2 is directly based on user input.
When arg2 is for example "C:\Windows\System32\cmd.exe" the arg1 parameter will be completely ignored and you grant the users of your API or server application full access to the whole file system.
So please be very careful with using this method!
I came up with this solution that should (afaik) be secure:
public static string SecurePathCombine(params string[] paths)
{
string combinedPath = "";
foreach (string path in paths)
{
string newPath = Path.Combine(combinedPath, path);
if (!newPath.StartsWith(combinedPath))
return null;
combinedPath = newPath;
}
if (Path.GetFullPath(combinedPath) != combinedPath)
return null;
return combinedPath;
}
Edit: There is a new Path.Join() method now. Please use that one instead of the code above.
I believe Path.FullPath will do what you need (I didn't test this though):
string newPath = Path.Combine(_myRootFolder, _myUserInput);
string newPath = Path.FullPath(newPath);
if (newPath.StartsWith(_myRootFolder)) ...
Well, in your example of an FTP server, you should set the users home-directory, and permissions appropriately, such that they can't navigate out of the folder. Any reason you can't do that?
You can parse input string and cut ../ with regex.

Categories

Resources