Formatting a Linux path in C# - c#

So I am making a file browser using the WinSCP library in C#. The files and folders from the remote server are loaded into a ListView, and I have an event on the ListView_DoubleClick event that will go and get the files for that folder. However my problem is, the "CurrentPath" returned from WinSCP is built like so;
"/eddata/T". Now if a user goes back up a directory, the path returned is "/eddata/T/../". If the user then goes into another folder called "Bob", the path now looks like; "/eddata/T/../Bob".
I want a way so I can display the current path in a user friendly way. So when a user is in the directory; "/eddata/T/" and they go up a level, a label should tell them they are in; "/eddata/";
This is my attempt but isn't working as expected, it doesn't deal the event where a user goes back up two directories at the same time;
private string FormatPathString(string input)
{
String working = input;
bool replacement = true;
while (replacement)
{
string[] splits = working.Split('/');
splits = splits.AsEnumerable().Where(x => x != String.Empty).ToArray();
int? found_index = null;
for (int i = splits.Count() - 1; i > 0; i--)
{
if (splits[i] == "..")
{
found_index = i;
break;
}
}
if (found_index.HasValue)
{
replacement = true;
splits = splits.Where((val, idx) => (idx != found_index) && (idx != found_index - 1)).ToArray();
working = String.Join("/", splits);
}
else
{
replacement = false;
}
}
return working;
}

You can use the Path class.
string pathWithDots= "/eddata/T/../Bob";
string pathWithoutDots = Path.GetFullPath(pathWithDots); // Result: c:\eddata\Bob
however the Path class assumes that you are using a windows path and adds C: and changes slashes to backslashes so you will need to remove the C: at the start and replace all back slashes with forward slashes.
string pathNx = pathWithoutDots.Substring(2).Replace("\\", "/"); // Result: /eddata/Bob

Related

Creating Subdirectory function in C#

I am currently attempting to create a function code that creates a subdirectory inside a user-specific path by having the user input the Directory path and then in main use the Directory.GetDirectories(arwgs) function to get a string array of there path.
This code works for the first attempt but after rerunning it again it creates a folder in same directory in the that I don't want to do again.
Good:
Directorys Created S:\Shop....\600\UnitCalFall
Bad:
Directorys Created S:\Shop\600\UnitCalFall\UnitCalFall
or
Directorys Created S:\Shop\600\UnitCalFall\UnitCalDone
I am trying to make the function as fast and integrative as possible so incase the user wants to create more than one or two folders.
The code is shown below:
static void UnitCalFolderCheck(string[] sDirectoryPath, string[] NewFolder)
{
//possible method can be constructed that checks for if a option UnitCallFolder has been created
for (int index = 0; index < sDirectoryPath.Length; index++)
{
//for each directory in the path if a folder named as UnitCalDONE in order to store CSV files data that has already been stored and conducted.
//ig a foldered labeled as such is already created then do not create this folder
string sCurrentPath = sDirectoryPath[index];
//check if current directory path already is created by the newfolder length path
//NEED TO CREATE A VARIABLE THAT CHECKS IF ANY OF THE SUBSTRINGS ARE TRUE AND IF SO DO NOT CHECK FOR NEW DIRECTORY
bool bexist = false;
//Console.WriteLine(sCurrentPath);
//also check if a the current path also has the UnitCalFolder Done already. This is because the newDirpath
//Will be a duplication of each folder and this can cause problems for the for loop
//append for each dirpath the folder information
for (int i = 0; i < NewFolder.Length; i++)
{
int NewFolderLength = NewFolder[i].Length;
string sNewDirPath = sCurrentPath + NewFolder[i];
string substring = sCurrentPath.Substring(sCurrentPath.Length - NewFolderLength);
//looping around the new possible created folders based on the substring paths
foreach (string x in NewFolder)
{
//THIS DOESNT CHECK IF FOLDER IS DIFFERENT FROM THE OTHER CONTAINER
// Console.WriteLine(x);
if (!substring.Contains(x)) //not working propery
{
bexist = true;
}
else
{
bexist = false;
}
}
if (!Directory.Exists(sNewDirPath) && (bexist == true) )
{
Directory.CreateDirectory(sNewDirPath);
Console.WriteLine("Directorys Created" + sNewDirPath);
}
}
}
}
*A crude way of fixing but when looking back this can work for folders with the suffix "UnitCal". At least for my directory. Not the most elegant but works.
static void UnitCalFolderCheck(string[] sDirectoryPath, string[] NewFolder)
{
//possible method can be constructed that checks for if a option UnitCallFolder has been created
for (int index = 0; index < sDirectoryPath.Length; index++)
{
//for each directory in the path if a folder named as UnitCalDONE in order to store CSV files data that has already been stored and conducted.
//ig a foldered labeled as such is already created then do not create this folder
string sCurrentPath = sDirectoryPath[index];
//Console.WriteLine(sCurrentPath);
//int[] iexist = new int[NewFolder.Count()]; //if substring exist already then dont create new directory
//int inotexist = 0;
string sNewDirPath;
string FolderIndexPath = "";
//for every new folder in the path check if the directory with substring already exist
for(int x = 0; x < NewFolder.Length; x++)
{
int NewFolderLength = NewFolder.Length; //length of the new folder to append to newdirpath string
//string substring = sCurrentPath.Substring(sCurrentPath.Length - NewFolderLength);
//UnitCalDone folder first iteration
//UNitCalFall folder secnond iteration
Console.WriteLine("========================================================================");
Console.WriteLine(sCurrentPath);
Console.WriteLine(NewFolder[x]);
if (!sCurrentPath.Contains("UnitCal"))
{
// iexist[x] = 0;
sNewDirPath = sCurrentPath + NewFolder[x];
// Determine whether the directory exists.
if (!Directory.Exists(sNewDirPath))
{
//check if new path already exist if so then do nothing
Console.WriteLine("NEWPATH->>>");
//Directory.CreateDirectory(sNewDirPath);
Console.WriteLine(sNewDirPath); //check that none of this values contain the selected values
}
}
else
{
//do nothing
}
}
}//end of for loop method
}//end of unitCalFolderCheckr code here*

Search parent directory from DirectoryInfo

Is there any way to search for the particular parent directory?
I know I can get the parent of the directory using this
Directory.GetParent(Directory.GetCurrentDirectory()).FullName
But this returns immediate parent, is there any way I can kind of search for particular parent in the directory hierarchy of the path?
EDIT
What I am trying to achieve is, say if I have current directory like this
C:/Project/Source/Dev/Database
So I want to reach to the directory Source
I know I can reach it by calling GetParent method twice but this I don't think is the right way to do it because what if in future my file current directory changes and it goes further down.
So I want some full proof way where I can directly find the path of the directory Source no matter how deep I am in the current directory because that is for sure that I will be inside directory Source
So something like
FindParent('Source')
You can try something like this (for loop):
private static IEnumerable<String> ParentDirectories(string directory = null) {
for (string dir = null == directory ? Directory.GetCurrentDirectory() : directory;
dir != null;
dir = Directory.GetParent(dir)?.FullName)
yield return dir;
}
Demo:
var demo = string.Join(Environment.NewLine,
ParentDirectories(#"C:/Project/Source/Dev/Database"));
Console.Write(demo);
Outcome:
C:/Project/Source/Dev/Database // initial directory
C:\Project\Source\Dev // and its all parents
C:\Project\Source
C:\Project
C:\
If you don't want to include directory itself, add .Skip(1):
var demo = string.Join(Environment.NewLine,
ParentDirectories(#"C:/Project/Source/Dev/Database").Skip(1));
Finally, if you want to find out a parent directory which ends by Source:
string dirName = "Source";
string myParent = ParentDirectories(#"C:/Project/Source/Dev/Database")
.FirstOrDefault(dir => string.Equals(
dirName,
new DirectoryInfo(dir).Name,
StringComparison.OrdinalIgnoreCase));
Console.Write(myParent);
Outcome:
C:\Project\Source
Directory.GetCurrentDirectory() returns a string that represents the full absolute path of the current directory.
If you want to get the path of a specific parent directory, you can simply use substring:
var path = Directory.GetCurrentDirectory(); // Suppose C:/Project/Source/Dev/Database
var sourceDir = new string[] {Path.DirectorySeparatorChar + "Source" + Path.DirectorySeparatorChar,
Path.AltDirectorySeparatorChar + "Source" + Path.AltDirectorySeparatorChar};
var sourcePath = path.IndexOf(sourceDir[0], StringComparison.OrdinalIgnoreCase) > -1 ?
path.Substring(0, path.IndexOf(sourceDir[0]) + sourceDir[0].Length) :
path.IndexOf(sourceDir[1], StringComparison.OrdinalIgnoreCase) > -1 ?
path.Substring(0, path.IndexOf(sourceDir[1]) + sourceDir[1].Length) :
null;
I've used Path.DirectorySeparatorChar and Path.AltDirectorySeparatorChar as separators so that the code will work the same on each platform.
Two possibles without anymore additional information about your situation:
DirectoryInfo.GetDirectories would get you all the child directories of the Current directory so you would need to switch your current to the root + 1
System.IO.Path.Combine(myPath, "..") which would act more like cd ..
Actually I thought there is an already existing way or function but if I have to write it myself then this solution I wrote worked for me
private static string GetParent(string directoryPath, string parent)
{
DirectoryInfo directory = new DirectoryInfo(directoryPath);
while (directory.Parent!=null)
{
if (directory.Parent.Name.ToLower() == parent.ToLower())
{
return directory.Parent.FullName;
}
directory = directory.Parent;
}
return null;
}
When traversing any kind of sequence (a sequence of numbers, a sequence of directories, a sequence of nodes in a graph), you have the option of employing recursion.
Directory structures (when ignoring links of any kind) are a subset of the data structure known as a Directed Acyclic Graph (or DAG) - this subset typically doesn't rejoin and fans out forever (so long as the operating system allows for the given depth of your nested directories). We typically refer to this as a Tree structure.
When put in this light, its probably no surprise to most that the concept of recursion surfaces because its quite common for programmers to apply recursion to traverse down a tree. However, whether you traverse up or down a tree is simply an implementation detail.
There is no reason you cannot use recursion to also traverse up a tree.
Here is a simple console app (written using .net6 conventions & C#10 syntax) that you can study, and then perhaps apply to solve future problems.
using System.Runtime.InteropServices; // For the [Optional] attribute
var dir = Directory.GetCurrentDirectory();
var file = Directory.GetFiles(dir).First();
var projFile = DirectoryRecursor.RecurseUpwardsUntilFileIsFoundWith(".csproj", file, 5);
Console.WriteLine(projFile);
public static class DirectoryRecursor
{
public static FileInfo? RecurseUpwardsUntilFileIsFoundWith(
string stringToMatch,
string sourceFile,
[Optional] int? maxParentDirLevel)
{
if (maxParentDirLevel is not null && maxParentDirLevel == 0) return null; // try and stave off disaster
var dirName = Path.GetDirectoryName(sourceFile);
if (dirName is null) return null;
var csprojFile = Directory.GetFiles(dirName).Where(x => x.EndsWith(stringToMatch)).SingleOrDefault();
if (csprojFile is null)
{
if (ThereIsAParentDirectory(new DirectoryInfo(sourceFile), out var parentDir))
{
return RecurseUpwardsUntilFileIsFoundWith(stringToMatch, parentDir.FullName, maxParentDirLevel - 1);
}
else
{
return null;
}
}
return new FileInfo(csprojFile);
}
public static bool ThereIsAParentDirectory(DirectoryInfo dir, out DirectoryInfo parentDir)
{
if (dir.Parent is not null)
{
parentDir = dir.Parent;
return dir.Parent.Exists;
}
parentDir = dir;
return false;
}
}
A quick side note:
An example of applied recursion both up and down a tree (which I appologize is not currently open source), is the conversation builder over at www.palavyr.com. This conversation tree is implemented as a double linked list to facilitate recursion both up and down the conversation tree. I'm planning on producing a technical blog post explaining this implementation - I'll update this response with that once I've assembled it.

Validate to prevent a path string to go up to parent folder

My business logic is accepting a folder path string to read a folder/file. However as security dictates, the user can only access that folder. For example:
Their folder is: C:\foo\user\bar, they can access C:\foo\user\bar\data\.a.b..txt by https://www.example.com/download?path=data/.a.b..txt
However, I want to prevent user from entering something that could make them go up a folder and see data of other. Here is my current code:
var result = this.ResultFolder; // The user folder (\user\bar as in the example)
if (!string.IsNullOrEmpty(path))
{
path = path.Replace("/", #"\");
if (path.StartsWith(#"\"))
{
path = path.Substring(1);
}
if (path.StartsWith('\\') || path.Contains("..\\"))
{
throw new InvalidDataException("Forbidden Path.");
}
result = Path.Combine(result, path);
}
Basically, what I do:
Replace all / into \ so I only have to worry about one separation character.
The request allows path to start with \ , it counts as nothing.
Now if user try to be malicious (by using \\ to go to root directory), or trying to go up a level by using ..\ (note before I used .. only, but get false case because it is valid file/folder name)
Is it correct and safe yet? Is there any framework method that helps with this?
Here's a solution that uses Path.GetFullPath(string path):
Create this function:
private static bool VerifyPathUnderRoot(string pathToVerify, string rootPath = ".")
{
var fullRoot = Path.GetFullPath(rootPath);
var fullPathToVerify = Path.GetFullPath(pathToVerify);
return fullPathToVerify.StartsWith(fullRoot);
}
Then you can test it with code like this:
var paths = new[]
{
"somepath/somefile.xxx",
"..\\somepath/somefile.xxx",
#"C:\this\that\the.other",
};
foreach (var path in paths)
{
var isOk = VerifyPathUnderRoot(path);
var okString = isOk ? "OK" : "No";
Debug.WriteLine($"{okString}: {path}");
}
which results in this in the Output pane of the debugger:
OK: somepath/somefile.xxx
No: ..\somepath/somefile.xx
No: C:\this\that\the.other
I use GetFullPath twice to canonicalize the paths (making sure that all slashes end up the same, etc.).

File.Exists not working in unity

I'm trying to write a script so the text of a save button changes if it has found a save file in that slot. However, my script cannot seem to find the file no matter what I do. Here's what I have right now.
if (File.Exists ("save1.dat")) {
//set button text
} else {
Debug.Log ("Failure");
}
I've tried multiple different variations on this. I've tried it with different files, different file extensions, including the Application.dataPath, using Resources.Load, but nothing works. For some reason, these functions cannot seem to find any files in my unity project, despite the fact I can see them clearly in both the unity editor and my file explorer. What are some reasons this might be happening? Are there ways to circumvent this?
The file path you are asking for is not a valid file path. You need to use the Application.dataPath as a root directory and make sure that it ends in a / before appending a file. You may also have to replace \ with / (looking at my own code).
This is sort of a hodgepodge, but I use this to determine the application directory for file IO:
public static class Configuration {
public static string currentBaseDirectory = "";
public static string currentDirectory = "";
public static void loadCurrentDirectory ()
{
currentDirectory = Application.dataPath;
currentDirectory = currentDirectory.Replace( #"\", "/" );
bool hasFoundMatch = false;
if ( !currentDirectory.EndsWith( "/" ) )
currentDirectory += "/";
switch (Application.platform) {
case RuntimePlatform.OSXEditor: //<path to project folder>/Assets
case RuntimePlatform.WindowsEditor:
if(currentDirectory.EndsWith("Assets/")) {
currentDirectory = currentDirectory.Substring(0, currentDirectory.LastIndexOf( "Assets/" ) );
currentDirectory += "RuntimeData/";
hasFoundMatch = true;
}
break;
case RuntimePlatform.WindowsPlayer: //<path to executablename_Data folder>
break;
case RuntimePlatform.OSXPlayer: //<path to player app bundle>/Contents
if(currentDirectory.EndsWith(".app/Contents/")) {
currentDirectory = currentDirectory.Substring(0, currentDirectory.LastIndexOf( ".app/Contents/" ) );
currentDirectory += "RuntimeData/";
hasFoundMatch = true;
}
break;
case RuntimePlatform.OSXDashboardPlayer: //<path to the dashboard widget bundle>
case RuntimePlatform.WindowsWebPlayer: //not supported
case RuntimePlatform.OSXWebPlayer:
default:
hasFoundMatch = false;
break;
}
if (!hasFoundMatch) {
currentDirectory = Path.GetFullPath("RuntimeData/");
currentDirectory = currentDirectory.Replace(#"\", "/");
}
if (!Directory.Exists( currentDirectory)) {
for (int i = 0; i < 3; i++)
currentDirectory = currentDirectory.Substring( 0, currentDirectory.LastIndexOf( "/" ) );
currentDirectory += "/RuntimeData/";
}
currentBaseDirectory = currentDirectory.Replace("/RuntimeData", "");
}
}
This allows me to have a RuntimeData directory next to Assets that I can put things like save files in. This folder then ships with the executable when published (although you might want a clean copy, free from any dev testing saves ;) ).

How to convert a relative path to an absolute path in a Windows application?

How do I convert a relative path to an absolute path in a Windows application?
I know we can use server.MapPath() in ASP.NET. But what can we do in a Windows application?
I mean, if there is a .NET built-in function that can handle that...
Have you tried:
string absolute = Path.GetFullPath(relative);
? Note that that will use the current working directory of the process, not the directory containing the executable. If that doesn't help, please clarify your question.
If you want to get the path relative to your .exe then use
string absolute = Path.Combine(Application.ExecutablePath, relative);
This one works for paths on different drives, for drive-relative paths and for actual relative paths. Heck, it even works if the basePath isn't actually absolute; it always uses the current working directory as final fallback.
public static String GetAbsolutePath(String path)
{
return GetAbsolutePath(null, path);
}
public static String GetAbsolutePath(String basePath, String path)
{
if (path == null)
return null;
if (basePath == null)
basePath = Path.GetFullPath("."); // quick way of getting current working directory
else
basePath = GetAbsolutePath(null, basePath); // to be REALLY sure ;)
String finalPath;
// specific for windows paths starting on \ - they need the drive added to them.
// I constructed this piece like this for possible Mono support.
if (!Path.IsPathRooted(path) || "\\".Equals(Path.GetPathRoot(path)))
{
if (path.StartsWith(Path.DirectorySeparatorChar.ToString()))
finalPath = Path.Combine(Path.GetPathRoot(basePath), path.TrimStart(Path.DirectorySeparatorChar));
else
finalPath = Path.Combine(basePath, path);
}
else
finalPath = path;
// resolves any internal "..\" to get the true full path.
return Path.GetFullPath(finalPath);
}
It's a bit older topic, but it might be useful for someone.
I have solved a similar problem, but in my case, the path was not at the beginning of the text.
So here is my solution:
public static class StringExtension
{
private const string parentSymbol = "..\\";
private const string absoluteSymbol = ".\\";
public static String AbsolutePath(this string relativePath)
{
string replacePath = AppDomain.CurrentDomain.BaseDirectory;
int parentStart = relativePath.IndexOf(parentSymbol);
int absoluteStart = relativePath.IndexOf(absoluteSymbol);
if (parentStart >= 0)
{
int parentLength = 0;
while (relativePath.Substring(parentStart + parentLength).Contains(parentSymbol))
{
replacePath = new DirectoryInfo(replacePath).Parent.FullName;
parentLength = parentLength + parentSymbol.Length;
};
relativePath = relativePath.Replace(relativePath.Substring(parentStart, parentLength), string.Format("{0}\\", replacePath));
}
else if (absoluteStart >= 0)
{
relativePath = relativePath.Replace(".\\", replacePath);
}
return relativePath;
}
}
Example:
Data Source=.\Data\Data.sdf;Persist Security Info=False;
Data Source=..\..\bin\Debug\Data\Data.sdf;Persist Security Info=False;

Categories