This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
RomVault/ROMVault2/IO/RVIO.cs

607 lines
22 KiB
C#
Raw Normal View History

2014-09-23 12:06:15 -07:00
/******************************************************
* ROMVault2 is written by Gordon J. *
* Contact gordon@romvault.com *
* Copyright 2014 *
******************************************************/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace ROMVault2.IO
{
[Flags]
[ComVisible(true)]
[Serializable]
public enum FileAttributes
{
ReadOnly = 1,
Hidden = 2,
System = 4,
Directory = 16,
Archive = 32,
Device = 64,
Normal = 128,
Temporary = 256,
SparseFile = 512,
ReparsePoint = 1024,
Compressed = 2048,
Offline = 4096,
NotContentIndexed = 8192,
Encrypted = 16384,
}
public static class Error
{
public static int GetLastError()
{
return Marshal.GetLastWin32Error();
}
}
public class FileInfo
{
public string Name;
public string FullName;
public long LastWriteTime;
public long Length;
public int fileAttributes;
public bool isHidden
{
get { return (fileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0; }
}
public FileInfo()
{ }
public FileInfo(string path)
{
FullName = path;
Name = Path.GetFileName(path);
string fileName = NameFix.AddLongPathPrefix(path);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
bool b = Win32Native.GetFileAttributesEx(fileName, 0, ref wIn32FileAttributeData);
if (!b || (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0) return;
Length = Convert.Length(wIn32FileAttributeData.fileSizeHigh, wIn32FileAttributeData.fileSizeLow);
LastWriteTime = Convert.Time(wIn32FileAttributeData.ftLastWriteTimeHigh, wIn32FileAttributeData.ftLastWriteTimeLow);
fileAttributes = wIn32FileAttributeData.fileAttributes;
}
}
public class DirectoryInfo
{
public string Name;
public string FullName;
public long LastWriteTime;
public int fileAttributes;
public bool isHidden
{
get { return (fileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0; }
}
public DirectoryInfo()
{ }
public DirectoryInfo(string path)
{
FullName = path;
Name = Path.GetFileName(path);
string fileName = NameFix.AddLongPathPrefix(path);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
bool b = Win32Native.GetFileAttributesEx(fileName, 0, ref wIn32FileAttributeData);
if (!b || (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0) return;
LastWriteTime = Convert.Time(wIn32FileAttributeData.ftLastWriteTimeHigh, wIn32FileAttributeData.ftLastWriteTimeLow);
fileAttributes = wIn32FileAttributeData.fileAttributes;
}
public DirectoryInfo[] GetDirectories(bool includeHidden = true)
{
return GetDirectories("*", includeHidden);
}
public DirectoryInfo[] GetDirectories(string SearchPattern, bool includeHidden = true)
{
List<DirectoryInfo> dirs = new List<DirectoryInfo>();
string dirName = NameFix.AddLongPathPrefix(FullName);
Win32Native.WIN32_FIND_DATA findData = new Win32Native.WIN32_FIND_DATA();
SafeFindHandle findHandle = Win32Native.FindFirstFile(dirName + @"\" + SearchPattern, findData);
if (!findHandle.IsInvalid)
{
do
{
string currentFileName = findData.cFileName;
// if this is a directory, find its contents
if ((findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0) continue;
if (currentFileName == "." || currentFileName == "..") continue;
if (!includeHidden && (findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0) continue;
DirectoryInfo di = new DirectoryInfo
{
Name = currentFileName,
FullName = Path.Combine(FullName, currentFileName),
LastWriteTime = Convert.Time(findData.ftLastWriteTimeHigh, findData.ftLastWriteTimeLow),
fileAttributes = findData.dwFileAttributes
};
dirs.Add(di);
}
while (Win32Native.FindNextFile(findHandle, findData));
}
// close the find handle
findHandle.Dispose();
return dirs.ToArray();
}
public FileInfo[] GetFiles()
{
return GetFiles("*");
}
public FileInfo[] GetFiles(string SearchPattern, bool includeHidden = true)
{
List<FileInfo> files = new List<FileInfo>();
string dirName = NameFix.AddLongPathPrefix(FullName);
Win32Native.WIN32_FIND_DATA findData = new Win32Native.WIN32_FIND_DATA();
SafeFindHandle findHandle = Win32Native.FindFirstFile(dirName + @"\" + SearchPattern, findData);
if (!findHandle.IsInvalid)
{
do
{
string currentFileName = findData.cFileName;
// if this is a directory, find its contents
if ((findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0) continue;
if (!includeHidden && (findData.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_HIDDEN) != 0) continue;
FileInfo fi = new FileInfo
{
Name = currentFileName,
FullName = Path.Combine(FullName, currentFileName),
Length = Convert.Length(findData.nFileSizeHigh, findData.nFileSizeLow),
LastWriteTime = Convert.Time(findData.ftLastWriteTimeHigh, findData.ftLastWriteTimeLow),
fileAttributes = findData.dwFileAttributes
};
files.Add(fi);
}
while (Win32Native.FindNextFile(findHandle, findData));
}
// close the find handle
findHandle.Dispose();
return files.ToArray();
}
}
public static class Directory
{
public static bool Exists(string path)
{
string fixPath = NameFix.AddLongPathPrefix(path);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
bool b = Win32Native.GetFileAttributesEx(fixPath, 0, ref wIn32FileAttributeData);
return b && (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) != 0;
}
public static void Move(String sourceDirName, String destDirName)
{
if (sourceDirName == null)
throw new ArgumentNullException("sourceDirName");
if (sourceDirName.Length == 0)
throw new ArgumentException("Argument_EmptyFileName", "sourceDirName");
if (destDirName == null)
throw new ArgumentNullException("destDirName");
if (destDirName.Length == 0)
throw new ArgumentException("Argument_EmptyFileName", "destDirName");
String fullsourceDirName = NameFix.AddLongPathPrefix(sourceDirName);
String fulldestDirName = NameFix.AddLongPathPrefix(destDirName);
if (!Win32Native.MoveFile(fullsourceDirName, fulldestDirName))
{
int hr = Marshal.GetLastWin32Error();
if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // Source dir not found
{
throw new Exception("ERROR_PATH_NOT_FOUND " + fullsourceDirName);
}
if (hr == Win32Native.ERROR_ACCESS_DENIED) // WinNT throws IOException. This check is for Win9x. We can't change it for backcomp.
{
throw new Exception("UnauthorizedAccess_IODenied_Path" + sourceDirName);
}
}
}
public static void Delete(String path)
{
String fullPath = NameFix.AddLongPathPrefix(path);
Win32Native.RemoveDirectory(fullPath);
}
public static void CreateDirectory(String path)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Length == 0)
throw new ArgumentException("Argument_PathEmpty");
String fullPath = NameFix.AddLongPathPrefix(path);
Win32Native.CreateDirectory(fullPath, IntPtr.Zero);
}
}
public static class File
{
public static bool Exists(string path)
{
string fixPath = NameFix.AddLongPathPrefix(path);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA wIn32FileAttributeData = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
bool b = Win32Native.GetFileAttributesEx(fixPath, 0, ref wIn32FileAttributeData);
return b && (wIn32FileAttributeData.fileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY) == 0;
}
public static void Copy(String sourceFileName, string destfileName)
{
Copy(sourceFileName, destfileName, true);
}
public static void Copy(String sourceFileName, String destFileName, bool overwrite)
{
if (sourceFileName == null || destFileName == null)
throw new ArgumentNullException((sourceFileName == null ? "sourceFileName" : "destFileName"), "ArgumentNull_FileName");
if (sourceFileName.Length == 0 || destFileName.Length == 0)
throw new ArgumentException("Argument_EmptyFileName", (sourceFileName.Length == 0 ? "sourceFileName" : "destFileName"));
String fullSourceFileName = NameFix.AddLongPathPrefix(sourceFileName);
String fullDestFileName = NameFix.AddLongPathPrefix(destFileName);
bool r = Win32Native.CopyFile(fullSourceFileName, fullDestFileName, !overwrite);
if (!r)
{
// Save Win32 error because subsequent checks will overwrite this HRESULT.
int errorCode = Marshal.GetLastWin32Error();
String fileName = destFileName;
/*
if (errorCode != Win32Native.ERROR_FILE_EXISTS)
{
// For a number of error codes (sharing violation, path
// not found, etc) we don't know if the problem was with
// the source or dest file. Try reading the source file.
using (SafeFileHandle handle = Win32Native.UnsafeCreateFile(fullSourceFileName, FileStream.GENERIC_READ, FileShare.Read, null, FileMode.Open, 0, IntPtr.Zero))
{
if (handle.IsInvalid)
fileName = sourceFileName;
}
if (errorCode == Win32Native.ERROR_ACCESS_DENIED)
{
if (Directory.InternalExists(fullDestFileName))
throw new IOException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Arg_FileIsDirectory_Name"), destFileName), Win32Native.ERROR_ACCESS_DENIED, fullDestFileName);
}
}
__Error.WinIOError(errorCode, fileName);
*/
}
}
public static void Move(String sourceFileName, String destFileName)
{
if (sourceFileName == null || destFileName == null)
throw new ArgumentNullException((sourceFileName == null ? "sourceFileName" : "destFileName"), "ArgumentNull_FileName");
if (sourceFileName.Length == 0 || destFileName.Length == 0)
throw new ArgumentException("Argument_EmptyFileName", (sourceFileName.Length == 0 ? "sourceFileName" : "destFileName"));
String fullSourceFileName = NameFix.AddLongPathPrefix(sourceFileName);
String fullDestFileName = NameFix.AddLongPathPrefix(destFileName);
if (!Exists(fullSourceFileName))
throw new Exception("ERROR_FILE_NOT_FOUND" + fullSourceFileName);
if (!Win32Native.MoveFile(fullSourceFileName, fullDestFileName))
{
int hr = Marshal.GetLastWin32Error();
throw new Exception("ERROR_MOVING_FILE. Error Code ("+hr+")");
}
}
public static void Delete(String path)
{
string fixPath = NameFix.AddLongPathPrefix(path);
if (!Win32Native.DeleteFile(fixPath))
{
int hr = Marshal.GetLastWin32Error();
if (hr != Win32Native.ERROR_FILE_NOT_FOUND)
throw new Exception("Error while deleting file :" + path);
}
}
public static bool SetAttributes(String path, FileAttributes fileAttributes)
{
String fullPath = NameFix.AddLongPathPrefix(path);
return Win32Native.SetFileAttributes(fullPath, (int)fileAttributes);
}
private const int ERROR_INVALID_PARAMETER = 87;
private const int ERROR_ACCESS_DENIED = 0x5;
}
public static class Path
{
public static readonly char DirectorySeparatorChar = '\\';
public static readonly char AltDirectorySeparatorChar = '/';
public static readonly char VolumeSeparatorChar = ':';
public static string GetExtension(String path)
{
return System.IO.Path.GetExtension(path);
}
public static string Combine(string path1, string path2)
{
if (path1 == null || path2 == null)
throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
//CheckInvalidPathChars(path1);
//CheckInvalidPathChars(path2);
if (path2.Length == 0)
return path1;
if (path1.Length == 0)
return path2;
if (IsPathRooted(path2))
return path2;
char ch = path1[path1.Length - 1];
if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar && ch != VolumeSeparatorChar)
return path1 + DirectorySeparatorChar + path2;
return path1 + path2;
}
private static bool IsPathRooted(String path)
{
if (path != null)
{
//CheckInvalidPathChars(path);
int length = path.Length;
if (
(length >= 1 && (path[0] == DirectorySeparatorChar ||
path[0] == AltDirectorySeparatorChar)) ||
(length >= 2 && path[1] == VolumeSeparatorChar)
) return true;
}
return false;
}
/*
private static void CheckInvalidPathChars(string path)
{
for (int index = 0; index < path.Length; ++index)
{
int num = path[index];
switch (num)
{
case 34:
case 60:
case 62:
case 124:
ReportError.SendErrorMessage("Invalid Character " + num + " in filename " + path);
continue;
default:
if (num >= 32)
continue;
goto case 34;
}
}
}
*/
public static string GetFileNameWithoutExtension(string path)
{
return System.IO.Path.GetFileNameWithoutExtension(path);
}
public static string GetFileName(String path)
{
return System.IO.Path.GetFileName(path);
}
public static String GetDirectoryName(String path)
{
if (path != null)
{
int root = GetRootLength(path);
int i = path.Length;
if (i > root)
{
i = path.Length;
if (i == root) return null;
while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar) ;
return path.Substring(0, i);
}
}
return null;
}
private static int GetRootLength(String path)
{
int i = 0;
int length = path.Length;
if (length >= 1 && (IsDirectorySeparator(path[0])))
{
// handles UNC names and directories off current drive's root.
i = 1;
if (length >= 2 && (IsDirectorySeparator(path[1])))
{
i = 2;
int n = 2;
while (i < length && ((path[i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar) || --n > 0)) i++;
}
}
else if (length >= 2 && path[1] == VolumeSeparatorChar)
{
// handles A:\foo.
i = 2;
if (length >= 3 && (IsDirectorySeparator(path[2]))) i++;
}
return i;
}
private static bool IsDirectorySeparator(char c)
{
return (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar);
}
}
public static class FileStream
{
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
// errorMessage = new Win32Exception(errorCode).Message;
public static int OpenFileRead(string path, out System.IO.Stream stream)
{
string filename = NameFix.AddLongPathPrefix(path);
SafeFileHandle hFile = Win32Native.CreateFile(filename,
GENERIC_READ,
System.IO.FileShare.Read,
IntPtr.Zero,
System.IO.FileMode.Open,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (hFile.IsInvalid)
{
stream = null;
return Marshal.GetLastWin32Error();
}
stream = new System.IO.FileStream(hFile, System.IO.FileAccess.Read);
return 0;
}
public static int OpenFileWrite(string path, out System.IO.Stream stream)
{
string filename = NameFix.AddLongPathPrefix(path);
SafeFileHandle hFile = Win32Native.CreateFile(filename,
GENERIC_WRITE,
System.IO.FileShare.None,
IntPtr.Zero,
System.IO.FileMode.Create,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (hFile.IsInvalid)
{
stream = null;
return Marshal.GetLastWin32Error();
}
stream = new System.IO.FileStream(hFile, System.IO.FileAccess.Write);
return 0;
}
}
public static class NameFix
{
public static string GetShortPath(string path)
{
int remove = 0;
string retPath;
if (path.StartsWith(@"\\"))
{
retPath = @"\\?\UNC\" + path.Substring(2);
remove = 8;
}
else
{
retPath = path;
if (path.Substring(1, 1) != ":")
retPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), retPath);
retPath = cleandots(retPath);
retPath = @"\\?\" + retPath;
remove = 4;
}
const int MAX_PATH = 300;
var shortPath = new StringBuilder(MAX_PATH);
Win32Native.GetShortPathName(retPath, shortPath, MAX_PATH);
retPath = shortPath.ToString();
retPath = retPath.Substring(remove);
if (remove == 8) retPath = "\\" + retPath;
return retPath;
}
internal static string AddLongPathPrefix(string path)
{
if (string.IsNullOrEmpty(path) || path.StartsWith(@"\\?\"))
return path;
if (path.StartsWith(@"\\"))
return @"\\?\UNC\" + path.Substring(2);
string retPath = path;
if (path.Substring(1, 1) != ":")
retPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), retPath);
retPath = cleandots(retPath);
return @"\\?\" + retPath;
}
private static string cleandots(string path)
{
string retPath = path;
while (retPath.Contains(@"\..\"))
{
int index = retPath.IndexOf(@"\..\");
string path1 = retPath.Substring(0, index);
string path2 = retPath.Substring(index + 4);
int path1Back = path1.LastIndexOf(@"\");
retPath = path1.Substring(0, path1Back + 1) + path2;
}
return retPath;
}
}
}