Read boot sector CD drive on macOS - c#

I am trying to read the boot sector of a cd drive so that I can extract its contents. Unfortunately, no matter what I do I can't seem to get it working. I have tried reading the directory as a file but get access denied. Tried reading right from /dev/disk# and got locked.
I have also tried checking and changing permissions, but nothing.
In Windows, I would use CreateFile & ReadFile from kernel32. I just am not sure what the macOS equivalent would be.
public static List<DriveInfo> GetDrives() => DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveType == DriveType.CDRom).ToList();
public static ReadDrives()
{
var drives = GetDrives()
foreach(var drive in drives)
{
var root = drive.RootDirectory.FullName;
using (var fp = File.OpenRead(#"/Volumes/Flash - Copy/"))
{
//extract boot here
}
}
}

This is not the best answer, but this works for me, no sudo needed.
It is at least a solution for now.
var command = $"-c \"umount {inputDisc} && dd if={inputDisc} of={outputfile} bs=32k count=1 && mount {inputDisc}\"";
Process.Start("/bin/bash", command);

Related

How to get the Full Path of a File?

I try to get the Full Path of a File. ie. calc
Input: calc
Expected output: C:\WINDOWS\system32\calc.exe
I could find out how to do it with PowerShell:
(Get-Command calc).Source
Or with CommandLine:
where.exe calc
But unfortunately I can not get it done with C#.
The documentation for Get-Command says:
Get-Command * gets all types of commands, including all of the non-PowerShell files in the Path environment variable ($env:Path), which it lists in the Application command type.
So we will need to get the Path environment variable and iterate over the directories it lists, looking for files with extensions that indicate the file is a program, for example "*.com" and "*.exe".
The problem with the Path environment variable is that it can become polluted with non-existent directories, so we will have to check for those.
The case of the filename and extension don't matter, so case-insensitive comparisons need to be made.
static void ShowPath(string progName)
{
var extensions = new List<string> { ".com", ".exe" };
string envPath = Environment.GetEnvironmentVariable("Path");
var dirs = envPath.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string d in dirs.Where(f => Directory.Exists(f)))
{
foreach (var f in (Directory.EnumerateFiles(d).
Where(thisFile => extensions.Any(h => Path.GetExtension(thisFile).Equals(h, StringComparison.InvariantCultureIgnoreCase)))))
{
if (Path.GetFileNameWithoutExtension(f).Equals(progName, StringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine(f);
return;
}
}
}
Console.WriteLine("Not found.");
}
static void Main(string[] args)
{
ShowPath("calc");
Console.ReadLine();
}
Output:
C:\WINDOWS\system32\calc.exe
There is always the possibility that the current user does not have permission to list the files from somewhere in the path, so checks should be added for that. Also, you might want to use StringComparison.CurrentCultureIgnoreCase for the comparison.
You can get the Pathenvironment variable, split it with ; as delimiter and loop over that result. Then, check if the file path + #"\" + name + ".exe" exists.
var findMe = "calc";
var pathes = Environment.GetEnvironmentVariable("Path").Split(';');
foreach (var path in pathes)
{
var testMe = $#"{path}\{findMe}.exe";
if (File.Exists(testMe))
{
Console.WriteLine(testMe);
}
}
This outputs :
C:\WINDOWS\system32\calc.exe
I do not know about any way of doing that exact thing from C# either. However the paths are usually well known and can be retreived via the SpecialFolders Enumeration:
using System;
using System.Diagnostics;
using System.IO;
namespace RunAsAdmin
{
class Program
{
static void Main(string[] args)
{
/*Note: Running a batch file (.bat) or similar script file as admin
Requires starting the interpreter as admin and handing it the file as Parameter
See documentation of Interpreting Programm for details */
//Just getting the Absolute Path for Notepad
string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
string FullPath = Path.Combine(windir, #"system32\notepad.exe");
//The real work part
//This is the programm to run
ProcessStartInfo startInfo = new ProcessStartInfo(FullPath);
//This tells it should run Elevated
startInfo.Verb = "runas";
//And that gives the order
//From here on it should be 100% identical to the Run Dialog (Windows+R), except for the part with the Elevation
System.Diagnostics.Process.Start(startInfo);
}
}
}
I did not just use System (37) back then, as I wrote it when x32/x86 Systems were still a thing. You would need to check how it resolves nowadays.
Note that most of those paths are duplicated in the PATH System Variable, so you could look it up: https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/
Path Variables in turn go back to the old DOS days. Basically if you gave the Commandline a command/filename it would try the build-in commands, then Executables in the current working Directory (.bat, .com, .exe), and then go look over the path directories to again look for executeables. And only if all that failed, would it complain.
I finally tried to combine all three answers and came up with this:
I post it here in case someone has the same problem.
public static string[] GetPathOf(string cmd)
{
var list = new List<string>();
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.Machine).Split(';'));
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.Process).Split(';'));
list.AddRange(Environment.GetEnvironmentVariable("path", EnvironmentVariableTarget.User).Split(';'));
list = list.Distinct().Where(e=>Directory.Exists(e)).SelectMany(e=> new DirectoryInfo(e).GetFiles()).Where(e=>Regex.IsMatch(e.Name,"(?i)^"+cmd+"\\.(?:exe|cmd|com)")).Select(e=>e.FullName).ToList();
return list.ToArray();
}

Zip Windows 10 Documents folder without including reparse points using System.IO.Compression

I'm writing a simple desktop application to copy files from one PC to another. Having trouble with the Windows 10 reparse points, specifically My Music. I thought was going to get away with one simple line of code:
ZipFile.CreateFromDirectory(documentsFolder, docSavePath + #"\Documents.zip", CompressionLevel.Optimal, false);
But not so, it crashes on the My Music folder. I've also tried a bunch of different ways of doing this, all with the same result - access denied. Can copying and/or zipping the Documents folder really be this hard? I doubt it, I'm just missing something. I tried elevating privileges and that didn't work, either. Anyone have an example of how to do this?
I was able figure out how to check for the ReparsePoint attribute, which was relatively easy, but then had to piece together how to loop through all the files and add them to the ZipArchive. The credit for the RecurseDirectory goes to this answer.
Then I added in what I learned about the reparse file attributes.
private void documentBackup(string docSavePath)
{
if (File.Exists(docSavePath + #"\Documents.zip")) File.Delete(docSavePath + #"\Documents.zip");
using (ZipArchive docZip = ZipFile.Open(docSavePath + "\\Documents.zip", ZipArchiveMode.Create))
{
foreach (FileInfo goodFile in RecurseDirectory(documentsFolder))
{
var destination = Path.Combine(goodFile.DirectoryName, goodFile.Name).Substring(documentsFolder.ToString().Length + 1);
docZip.CreateEntryFromFile(Path.Combine(goodFile.Directory.ToString(), goodFile.Name), destination);
}
}
}
public IEnumerable<FileInfo> RecurseDirectory(string path, List<FileInfo> currentData = null)
{
if (currentData == null)
currentData = new List<FileInfo>();
var directory = new DirectoryInfo(path);
foreach (var file in directory.GetFiles())
currentData.Add(file);
foreach (var d in directory.GetDirectories())
{
if ((d.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
{
continue;
}
else
{
RecurseDirectory(d.FullName, currentData);
}
}
return currentData;
}
It takes longer than I'd like to run - but after looking at this dang problem for days I'm just happy it works!

Search for ".myox" files on Computer

trying to write a small windows application for my company. the part i am stuck at the moment is trying to search the computer for ".myox" files (or say any file type). Below pasted is the code i have worked out. I am an amateur programmer trying to get started with coding. The issue am having at the moment with the code below is its skipping almost all locations on the computer with the exception coming up as "access denied". I have run the VS as admin, and i am an admin on the computer as well. Not sure what i am missing, but if someone can point me in the right direction, that would be amazing.
private void FindAllFiles()
{
int drvCount;
int drvSearchCount = 0;
DriveInfo[] allDrives = DriveInfo.GetDrives();
drvCount = allDrives.Count();
foreach (DriveInfo dr in allDrives)
{
lbAllFiles.Items.Clear();
drvSearchCount++;
//removable drives
if (!dr.IsReady)
break;
foreach (string dir in Directory.GetDirectories(dr.ToString()))
{
try
{
foreach (string files in Directory.GetFiles(dir, "*.myox"))
{
lbAllFiles.Items.Add(files);
}
}
catch (Exception Error)
{
}
}
if (drvSearchCount == drvCount)
break;
}
MessageBox.Show("Done searching your computer");
}
Thanks in Advance.
-Manu
I see few "potential" issues and will list them below.
First is that you're doing this on main ( UI ) thread which will block whole application giving you no feedback about current state. You can use Thread to get rid of this problem. Outcome from this operation will produce another issue which is accessing lbAllFiles because ( as i think ) it's part of the UI. You can easily get rid of this problem making a List<string> that can be filled during FindAllFiles operation and then assigned into lbAllFiles.Items.
Second issue is :
foreach (string files in Directory.GetFiles(dir, "*.myox"))
{
lbAllFiles.Items.Add(files);
}
Directory.GetFiles(...) will return only the files that are matching your pattern parameter so you can simply do :
var files = Directory.GetFiles(dir, "*.myox");
if ( files != null && files.Length > 0 )
lblAllFiles.Items.AddRange(files);
And finaly to get ( or check ) permission you can Demand() permissions as I've posted in the comment :
foreach (string dir in Directory.GetDirectories(dr.ToString()))
{
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, dir);
try
{
permission.Demand();
var files = Directory.GetFiles(dir, "*.myox");
if ( files != null && files.Length > 0 )
lblAllFiles.Items.AddRange(files);
}
catch (Exception Error)
{
}
}
Let me know if that helped you. If not I'll try to update my answer with another solution.
One thing i noticed in your code, is that you're not navigating through ALL directories and sub-directories. For that, where you call the GetDirectories function, not only send the path, but use the enumerator Alldirectories:
foreach (string dir in Directory.GetDirectories(dr.ToString(),System.IO.SearchOption.AllDirectories))

Prevent application being runned from network drive

I wonder if it was possible to prevent or at least detect if my application is being used from a network drive instead of a local folder/drive.
I wish to inform my user that he has to copy the sources and run them locally because of heavy performance pitfalls.
Get the path to where your executable has been executed from, get the root, then find out if it is a network drive.
var root = Path.GetPathRoot(Assembly.GetEntryAssembly().Location)
var driveInfo = new DriveInfo(root));
if (driveInfo.DriveType == DriveType.Network) {
// Alert that this will be slow.
}
Note that you should read the question I linked (How can I get the application's path in a .NET console application?), as there is potentially a bit more to it than the code above, depending on your exact scenario.
to prevent ArgumentException in case GetPathRoot returns \\Share\myshare
DriveInfo driveInfo = null;
try
{
driveInfo = new DriveInfo(Path.GetPathRoot(Assembly.GetEntryAssembly().Location));
}
catch (Exception)
{
}
if (driveInfo == null || driveInfo.DriveType == DriveType.Network)
{
//not allowed
}

Check if directory exists in my connected phone C#

When I plug in my iphone, I can access a folder named DCIM.
The file path is "This PC\Will-iPhone\Internal Storage\DCIM".
My question is how can I check to see if that folder exists? I need to know the way to check but not on a phone as it doesn't have C\ or H\ or whatever at the beginning of its file path.
Apparently, I cannot upload an image, but its just listed under devices and drivers as "Will-iPhone".
if (System.IO.Directory.Exists(#"\\Will-iPhone\Internal Storage\DCIM\"))
{
MessageBox.Show("Yes");
}
I've also tried with different amount of backslashes, having "This PC" at the start but nothing seems to work so far
Any help is appreciated. preferably C# btw
The iPhone (and other cameras) are so-called PTP devices and are not accessible using UNC paths. Instead, you would need to implement PTP yourself or find a suitable library (which might be hard according to a quick Google search).
Other than that, there is PTPdrive (no affiliation) which allegedly maps PTP devices to a drive letter.
Addendum: after all, iPhones can be accessed using WIA, so I jotted this (add a COM reference to Microsoft Windows Image Acquisition Library v2.0 to use):
using System.Collections.Generic;
using System.IO;
using System.Linq;
using WIA;
public static class WiaCopy
{
public static IEnumerable<IDeviceInfo> GetAppleDevices()
{
return new DeviceManager().DeviceInfos.Cast<IDeviceInfo>().Where(di =>
di.Type == WiaDeviceType.CameraDeviceType
&& di.Properties["Manufacturer"].get_Value() == "Apple Inc."
&& di.Properties["Description"].get_Value() == "Apple iPhone");
}
public static IEnumerable<Item> GetImgItems(IDeviceInfo deviceInfo)
{
var device = deviceInfo.Connect();
return device.Items.Cast<Item>().Where(i => i.Properties["Item Name"].get_Value().ToString().StartsWith("IMG"));
}
public static void TransferItem(Item item, string path)
{
// TODO: should use .mov for videos here
var targetName = item.Properties["Item Name"].get_Value() + ".jpg";
Directory.CreateDirectory(path);
item.Transfer().SaveFile(Path.Combine(path, targetName));
}
}
which can be used like so:
var savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Auto Import");
foreach (var iPhone in WiaCopy.GetAppleDevices())
{
foreach (var imgItem in WiaCopy.GetImgItems(iPhone))
{
WiaCopy.TransferItem(imgItem, Path.Combine(savePath, iPhone.Properties["Name"].get_Value()));
}
}
Note that this works for images only, for videos (although these start with IMG too), if found no way to copy them using WIA. For starters, the above should suffice.
check properties of DCIM folder there should be the full path.

Categories

Resources