xamarin-macios/tools/common/PathUtils.cs

204 строки
5.6 KiB
C#
Исходник Обычный вид История

using System;
2016-04-21 16:40:25 +03:00
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
2016-04-21 16:40:25 +03:00
namespace Xamarin.Utils
2016-04-21 16:40:25 +03:00
{
public static class PathUtils
{
static bool IsSeparator (char c)
{
return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar || c == Path.VolumeSeparatorChar;
}
static char ToOrdinalIgnoreCase (char c)
{
return (((uint) c - 'a') <= ((uint) 'z' - 'a')) ? (char) (c - 0x20) : c;
}
[DllImport ("/usr/lib/libc.dylib")]
static extern IntPtr realpath (string path, IntPtr buffer);
public static string ResolveSymbolicLinks (string path)
2016-04-21 16:40:25 +03:00
{
if (string.IsNullOrEmpty (path))
return path;
2016-04-21 16:40:25 +03:00
if (Path.DirectorySeparatorChar == '\\')
return Path.GetFullPath (path);
const int PATHMAX = 4096 + 1;
var buffer = IntPtr.Zero;
2016-04-21 16:40:25 +03:00
try {
buffer = Marshal.AllocHGlobal (PATHMAX);
var result = realpath (path, buffer);
return result == IntPtr.Zero ? path : Marshal.PtrToStringAuto (buffer);
2016-04-21 16:40:25 +03:00
} finally {
if (buffer != IntPtr.Zero)
Marshal.FreeHGlobal (buffer);
}
}
public static string AbsoluteToRelative (string baseDirectory, string absolute)
{
if (string.IsNullOrEmpty (baseDirectory))
2016-04-21 16:40:25 +03:00
return absolute;
// canonicalize the paths
baseDirectory = Path.GetFullPath (baseDirectory).TrimEnd (Path.DirectorySeparatorChar);
absolute = Path.GetFullPath (absolute);
int baseDirectoryStartIndex = baseDirectory.Length;
int absoluteStartIndex = absolute.Length;
int separators = 0;
int index = 0;
while (index < absolute.Length) {
if (ToOrdinalIgnoreCase (absolute[index]) != ToOrdinalIgnoreCase (baseDirectory[index]))
break;
if (IsSeparator (absolute[index])) {
baseDirectoryStartIndex = index;
absoluteStartIndex = index + 1;
separators++;
}
index++;
if (index >= baseDirectory.Length) {
if (index >= absolute.Length || IsSeparator (absolute[index])) {
baseDirectoryStartIndex = index;
absoluteStartIndex = index + 1;
separators++;
}
break;
}
}
if (separators == 0)
return absolute;
if (absoluteStartIndex >= absolute.Length)
return ".";
if (index >= absolute.Length && IsSeparator (baseDirectory[index])) {
absoluteStartIndex = index + 1;
baseDirectoryStartIndex = index;
}
int parentDirCount = 0;
while (baseDirectoryStartIndex < baseDirectory.Length) {
if (IsSeparator (baseDirectory[baseDirectoryStartIndex]))
parentDirCount++;
baseDirectoryStartIndex++;
}
var size = (parentDirCount * 3) + (absolute.Length - absoluteStartIndex);
var result = new char [size];
index = 0;
for (int i = 0; i < parentDirCount; i++) {
result[index++] = '.';
result[index++] = '.';
result[index++] = Path.DirectorySeparatorChar;
}
while (absoluteStartIndex < absolute.Length)
result[index++] = absolute[absoluteStartIndex++];
return new string (result);
}
public static string RelativeToAbsolute (string baseDirectory, string relative)
{
return Path.GetFullPath (Path.Combine (baseDirectory, relative));
}
[DllImport ("/usr/lib/libSystem.dylib", SetLastError = true)]
static extern int symlink (string path1, string path2);
public static bool Symlink (string target, string symlink)
{
return PathUtils.symlink (target, symlink) == 0;
}
public static void CreateSymlink (string symlink, string target)
{
FileDelete (symlink); // Delete any existing symlinks.
var rv = PathUtils.symlink (target, symlink);
if (rv != 0)
throw new Exception (string.Format ("Could not create the symlink '{0}': {1}", symlink, Marshal.GetLastWin32Error ()));
}
[DllImport ("/usr/lib/libSystem.dylib", SetLastError = true)]
static extern int readlink (string path, [Out] byte[] buffer, IntPtr len);
public static string GetSymlinkTarget (string path)
{
byte [] buffer = null;
int rv;
do {
buffer = new byte [(buffer?.Length ?? 0) + 1024];
rv = readlink (path, buffer, (IntPtr) (buffer.Length - 1));
} while (rv == buffer.Length - 1);
if (rv == -1)
throw new Exception (string.Format ("Could not readlink '{0}': {1}", path, Marshal.GetLastWin32Error ()));
return Encoding.UTF8.GetString (buffer, 0, rv);
}
[DllImport ("/usr/lib/libSystem.dylib")]
static extern int unlink (string pathname);
// File.Delete can't always delete symlinks (in particular if the symlink points to a file that doesn't exist).
public static void FileDelete (string file)
{
unlink (file);
// ignore any errors.
}
struct timespec {
public IntPtr tv_sec;
public IntPtr tv_nsec;
}
struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
public uint st_dev;
public ushort st_mode;
public ushort st_nlink;
public ulong st_ino;
public uint st_uid;
public uint st_gid;
public uint st_rdev;
public timespec st_atimespec;
public timespec st_mtimespec;
public timespec st_ctimespec;
public timespec st_birthtimespec;
public ulong st_size;
public ulong st_blocks;
public uint st_blksize;
public uint st_flags;
public uint st_gen;
public uint st_lspare;
public ulong st_qspare_1;
public ulong st_qspare_2;
}
[DllImport ("/usr/lib/libSystem.dylib", EntryPoint = "lstat$INODE64", SetLastError = true)]
static extern int lstat (string path, out stat buf);
public static bool IsSymlink (string file)
{
stat buf;
var rv = lstat (file, out buf);
if (rv != 0)
throw new Exception (string.Format ("Could not lstat '{0}': {1}", file, Marshal.GetLastWin32Error ()));
const int S_IFLNK = 40960;
return (buf.st_mode & S_IFLNK) == S_IFLNK;
}
2016-04-21 16:40:25 +03:00
}
}