Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Skovhede <kenneth@hexad.dk>2016-11-03 15:11:53 +0300
committerKenneth Skovhede <kenneth@hexad.dk>2016-11-03 15:11:53 +0300
commit1f7110503a25572a5070eb4913d9a485a6f44052 (patch)
tree3e88ff01d08558237812754b3ef4501f698ca41d
parent836d59105816df20022fd0ff4fd4e28364638383 (diff)
Updated unix symlinks handling to store correct metadata for symlinks
-rw-r--r--Duplicati/Library/Main/Operation/BackupHandler.cs2
-rw-r--r--Duplicati/Library/Snapshots/ISnapshotService.cs4
-rw-r--r--Duplicati/Library/Snapshots/ISystemIO.cs2
-rw-r--r--Duplicati/Library/Snapshots/LinuxSnapshot.cs6
-rw-r--r--Duplicati/Library/Snapshots/NoSnapshot.cs6
-rw-r--r--Duplicati/Library/Snapshots/NoSnapshotLinux.cs6
-rw-r--r--Duplicati/Library/Snapshots/NoSnapshotWindows.cs6
-rw-r--r--Duplicati/Library/Snapshots/SystemIOLinux.cs4
-rw-r--r--Duplicati/Library/Snapshots/SystemIOWindows.cs2
-rw-r--r--Duplicati/Library/Snapshots/WindowsSnapshot.cs6
-rw-r--r--thirdparty/UnixSupport/File.cs678
-rwxr-xr-xthirdparty/UnixSupport/UnixSupport.dllbin8192 -> 8192 bytes
12 files changed, 371 insertions, 351 deletions
diff --git a/Duplicati/Library/Main/Operation/BackupHandler.cs b/Duplicati/Library/Main/Operation/BackupHandler.cs
index e4a90b082..90e5df11a 100644
--- a/Duplicati/Library/Main/Operation/BackupHandler.cs
+++ b/Duplicati/Library/Main/Operation/BackupHandler.cs
@@ -835,7 +835,7 @@ namespace Duplicati.Library.Main.Operation
if (m_options.StoreMetadata)
{
- metadata = snapshot.GetMetadata(path);
+ metadata = snapshot.GetMetadata(path, attributes.HasFlag(System.IO.FileAttributes.ReparsePoint), m_symlinkPolicy == Options.SymlinkStrategy.Follow);
if (metadata == null)
metadata = new Dictionary<string, string>();
diff --git a/Duplicati/Library/Snapshots/ISnapshotService.cs b/Duplicati/Library/Snapshots/ISnapshotService.cs
index 2060a466e..314e8b66e 100644
--- a/Duplicati/Library/Snapshots/ISnapshotService.cs
+++ b/Duplicati/Library/Snapshots/ISnapshotService.cs
@@ -81,7 +81,9 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- Dictionary<string, string> GetMetadata(string file);
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink);
/// <summary>
/// Gets a value indicating if the path points to a block device
diff --git a/Duplicati/Library/Snapshots/ISystemIO.cs b/Duplicati/Library/Snapshots/ISystemIO.cs
index 417f0698b..cf3fef902 100644
--- a/Duplicati/Library/Snapshots/ISystemIO.cs
+++ b/Duplicati/Library/Snapshots/ISystemIO.cs
@@ -57,7 +57,7 @@ namespace Duplicati.Library.Snapshots
IEnumerable<string> EnumerateFileSystemEntries(string path);
void SetMetadata(string path, Dictionary<string, string> metdata, bool restorePermissions);
- Dictionary<string, string> GetMetadata(string path);
+ Dictionary<string, string> GetMetadata(string path, bool isSymlink, bool followSymlink);
}
}
diff --git a/Duplicati/Library/Snapshots/LinuxSnapshot.cs b/Duplicati/Library/Snapshots/LinuxSnapshot.cs
index 8978cfa26..e2a5d6b08 100644
--- a/Duplicati/Library/Snapshots/LinuxSnapshot.cs
+++ b/Duplicati/Library/Snapshots/LinuxSnapshot.cs
@@ -463,10 +463,12 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- public Dictionary<string, string> GetMetadata(string file)
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
var local = ConvertToSnapshotPath(FindSnapShotByLocalPath(file), file);
- return _sysIO.GetMetadata(local);
+ return _sysIO.GetMetadata(local, isSymlink, followSymlink);
}
/// <summary>
diff --git a/Duplicati/Library/Snapshots/NoSnapshot.cs b/Duplicati/Library/Snapshots/NoSnapshot.cs
index bd228a3e0..edfca74ba 100644
--- a/Duplicati/Library/Snapshots/NoSnapshot.cs
+++ b/Duplicati/Library/Snapshots/NoSnapshot.cs
@@ -176,7 +176,9 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- public abstract Dictionary<string, string> GetMetadata(string file);
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public abstract Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink);
/// <summary>
/// Gets a value indicating if the path points to a block device
@@ -189,7 +191,7 @@ namespace Duplicati.Library.Snapshots
/// Gets a unique hardlink target ID
/// </summary>
/// <returns>The hardlink ID</returns>
- /// <param name="file">The file or folder to examine</param>
+ /// <param name="path">The file or folder to examine</param>
public abstract string HardlinkTargetID(string path);
#endregion
}
diff --git a/Duplicati/Library/Snapshots/NoSnapshotLinux.cs b/Duplicati/Library/Snapshots/NoSnapshotLinux.cs
index cd586349e..a6d18c3b7 100644
--- a/Duplicati/Library/Snapshots/NoSnapshotLinux.cs
+++ b/Duplicati/Library/Snapshots/NoSnapshotLinux.cs
@@ -53,9 +53,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- public override Dictionary<string, string> GetMetadata(string file)
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public override Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
- return _sysIO.GetMetadata(file);
+ return _sysIO.GetMetadata(file, isSymlink, followSymlink);
}
/// <summary>
diff --git a/Duplicati/Library/Snapshots/NoSnapshotWindows.cs b/Duplicati/Library/Snapshots/NoSnapshotWindows.cs
index 00cb23c86..e708042ac 100644
--- a/Duplicati/Library/Snapshots/NoSnapshotWindows.cs
+++ b/Duplicati/Library/Snapshots/NoSnapshotWindows.cs
@@ -146,9 +146,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- public override Dictionary<string, string> GetMetadata(string file)
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public override Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
- return m_sysIO.GetMetadata(file);
+ return m_sysIO.GetMetadata(file, isSymlink, followSymlink);
}
/// <summary>
diff --git a/Duplicati/Library/Snapshots/SystemIOLinux.cs b/Duplicati/Library/Snapshots/SystemIOLinux.cs
index d6e8e1a72..2e05cabc9 100644
--- a/Duplicati/Library/Snapshots/SystemIOLinux.cs
+++ b/Duplicati/Library/Snapshots/SystemIOLinux.cs
@@ -165,12 +165,12 @@ namespace Duplicati.Library.Snapshots
Directory.Delete(NoSnapshot.NormalizePath(path), recursive);
}
- public Dictionary<string, string> GetMetadata(string file)
+ public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
var f = NoSnapshot.NormalizePath(file);
var dict = new Dictionary<string, string>();
- var n = UnixSupport.File.GetExtendedAttributes(f);
+ var n = UnixSupport.File.GetExtendedAttributes(f, isSymlink, followSymlink);
if (n != null)
foreach(var x in n)
dict["unix-ext:" + x.Key] = Convert.ToBase64String(x.Value);
diff --git a/Duplicati/Library/Snapshots/SystemIOWindows.cs b/Duplicati/Library/Snapshots/SystemIOWindows.cs
index cba47b071..c4b3cc44c 100644
--- a/Duplicati/Library/Snapshots/SystemIOWindows.cs
+++ b/Duplicati/Library/Snapshots/SystemIOWindows.cs
@@ -500,7 +500,7 @@ namespace Duplicati.Library.Snapshots
Alphaleonis.Win32.Filesystem.Directory.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All);
}
- public Dictionary<string, string> GetMetadata(string path)
+ public Dictionary<string, string> GetMetadata(string path, bool isSymlink, bool followSymlink)
{
var isDirTarget = path.EndsWith(DIRSEP);
var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path;
diff --git a/Duplicati/Library/Snapshots/WindowsSnapshot.cs b/Duplicati/Library/Snapshots/WindowsSnapshot.cs
index 78fd4b343..fd3f4d3ee 100644
--- a/Duplicati/Library/Snapshots/WindowsSnapshot.cs
+++ b/Duplicati/Library/Snapshots/WindowsSnapshot.cs
@@ -394,9 +394,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
- public Dictionary<string, string> GetMetadata(string file)
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
- return _ioWin.GetMetadata(GetSnapshotPath(file));
+ return _ioWin.GetMetadata(GetSnapshotPath(file), isSymlink, followSymlink);
}
/// <summary>
diff --git a/thirdparty/UnixSupport/File.cs b/thirdparty/UnixSupport/File.cs
index 18ace7fca..6bb48665b 100644
--- a/thirdparty/UnixSupport/File.cs
+++ b/thirdparty/UnixSupport/File.cs
@@ -1,335 +1,343 @@
-using System;
-using System.Collections.Generic;
-using Mono.Unix.Native;
-
-namespace UnixSupport
-{
- public static class File
- {
-
- private static readonly bool SUPPORTS_LLISTXATTR;
-
- static File ()
- {
- bool works = false;
- try
- {
- string[] v;
- Mono.Unix.Native.Syscall.llistxattr("/", out v);
- works = true;
- }
- catch (EntryPointNotFoundException e)
- {
- }
- catch
- {
- }
- SUPPORTS_LLISTXATTR = works;
- }
-
- /// <summary>
- /// Opens the file and honors advisory locking.
- /// </summary>
- /// <returns>A open stream that references the file</returns>
- /// <param name="path">The full path to the file</param>
- public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode)
- {
- return OpenExclusive(path, mode, (int)Mono.Unix.Native.FilePermissions.DEFFILEMODE);
- }
-
- /// <summary>
- /// Opens the file and honors advisory locking.
- /// </summary>
- /// <returns>A open stream that references the file</returns>
- /// <param name="path">The full path to the file</param>
- /// <param name="filemode">The file create mode</param>
- public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode, int filemode)
- {
- Flock lck;
- lck.l_len = 0;
- lck.l_pid = Syscall.getpid();
- lck.l_start = 0;
- lck.l_type = LockType.F_WRLCK;
- lck.l_whence = SeekFlags.SEEK_SET;
-
- OpenFlags flags = OpenFlags.O_CREAT;
- if (mode == System.IO.FileAccess.Read)
- {
- lck.l_type = LockType.F_RDLCK;
- flags |= OpenFlags.O_RDONLY;
- } else if (mode == System.IO.FileAccess.Write) {
- flags |= OpenFlags.O_WRONLY;
- } else {
- flags |= OpenFlags.O_RDWR;
- }
-
- int fd = Syscall.open(path, flags, (Mono.Unix.Native.FilePermissions)filemode);
- if (fd > 0)
- {
- //This does not work on OSX, it gives ENOTTY
- //int res = Syscall.fcntl(fd, Mono.Unix.Native.FcntlCommand.F_SETLK, ref lck);
-
- //This is the same (at least for our purpose, and works on OSX)
- int res = Syscall.lockf(fd, LockfCommand.F_TLOCK, 0);
-
- //If we have the lock, return the stream
- if (res == 0)
- return new Mono.Unix.UnixStream(fd);
- else
- {
- Mono.Unix.Native.Syscall.close(fd);
- throw new LockedFileException(path, mode);
- }
- }
-
- throw new BadFileException(path);
- }
-
- [Serializable]
- private class BadFileException : System.IO.IOException
- {
- public BadFileException(string filename)
- : base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError()))
- {
- }
- }
-
- [Serializable]
- private class LockedFileException : System.IO.IOException
- {
- public LockedFileException(string filename, System.IO.FileAccess mode)
- : base(string.Format("Unable to open the file \"{0}\" in mode {1}, error: {2} ({3})", filename, mode, Syscall.GetLastError(), (int)Syscall.GetLastError()))
- {
- }
- }
-
- [Serializable]
- private class FileAccesException : System.IO.IOException
- {
- public FileAccesException(string filename, string method)
- : base(string.Format("Unable to access the file \"{0}\" with method {1}, error: {2} ({3})", filename, method, Syscall.GetLastError(), (int)Syscall.GetLastError()))
- {
- }
- }
-
- /// <summary>
- /// Gets the symlink target for the given path
- /// </summary>
- /// <param name="path">The path to get the symlink target for</param>
- /// <returns>The symlink target</returns>
- public static string GetSymlinkTarget(string path)
- {
- System.Text.StringBuilder sb = new System.Text.StringBuilder(2048); //2kb, should cover utf16 * 1023 chars
- if (Mono.Unix.Native.Syscall.readlink(path, sb, (ulong)sb.Capacity) >= 0)
- return sb.ToString();
-
- throw new System.IO.FileLoadException(string.Format("Unable to get symlink for \"{0}\", error: {1} ({2})", path, Syscall.GetLastError(), (int)Syscall.GetLastError()));
- }
-
- /// <summary>
- /// Creates a new symlink
- /// </summary>
- /// <param name="path">The path to create the symbolic link entry</param>
- /// <param name="target">The path the symbolic link points to</param>
- public static void CreateSymlink(string path, string target)
- {
- if (Mono.Unix.Native.Syscall.symlink(target, path) != 0)
- throw new System.IO.IOException(string.Format("Unable to create symlink from \"{0}\" to \"{1}\", error: {2} ({3})", path, target, Syscall.GetLastError(), (int)Syscall.GetLastError()));
- }
-
- /// <summary>
- /// Enum that describes the different filesystem entry types
- /// </summary>
- public enum FileType
- {
- File,
- Directory,
- Symlink,
- Fifo,
- Socket,
- CharacterDevice,
- BlockDevice,
- Unknown
- }
-
- /// <summary>
- /// Gets the type of the file.
- /// </summary>
- /// <returns>The file type</returns>
- /// <param name="path">The full path to look up</param>
- public static FileType GetFileType(string path)
- {
-
- var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
- if (fse.IsRegularFile)
- return FileType.File;
- else if (fse.IsDirectory)
- return FileType.Directory;
- else if (fse.IsSymbolicLink)
- return FileType.Symlink;
- else if (fse.IsFifo)
- return FileType.Fifo;
- else if (fse.IsSocket)
- return FileType.Socket;
- else if (fse.IsCharacterDevice)
- return FileType.CharacterDevice;
- else if (fse.IsBlockDevice)
- return FileType.CharacterDevice;
- else
- return FileType.Unknown;
- }
-
-
- /// <summary>
- /// Gets the extended attributes.
- /// </summary>
- /// <returns>The extended attributes.</returns>
- /// <param name="path">The full path to look up</param>
- public static Dictionary<string, byte[]> GetExtendedAttributes(string path)
- {
- string[] values;
- var size = SUPPORTS_LLISTXATTR ? Mono.Unix.Native.Syscall.llistxattr(path, out values) : Mono.Unix.Native.Syscall.listxattr(path, out values);
- if (size < 0)
- {
- // In case the underlying filesystem does not support extended attributes,
- // we simply return that there are no attributes
- if (Syscall.GetLastError() == Errno.EOPNOTSUPP)
- return null;
-
- throw new FileAccesException(path, "llistxattr");
- }
-
- var dict = new Dictionary<string, byte[]>();
- foreach(var s in values)
- {
- byte[] v;
- var n = SUPPORTS_LLISTXATTR ? Mono.Unix.Native.Syscall.lgetxattr(path, s, out v) : Mono.Unix.Native.Syscall.getxattr(path, s, out v);
- if (n > 0)
- dict.Add(s, v);
- }
-
- return dict;
- }
-
- /// <summary>
- /// Sets an extended attribute.
- /// </summary>
- /// <param name="path">The full path to set the values for</param>
- /// <param name="key">The extended attribute key</param>
- /// <param name="value">The value to set</param>
- public static void SetExtendedAttribute(string path, string key, byte[] value)
- {
- Mono.Unix.Native.Syscall.setxattr(path, key, value);
- }
-
- /// <summary>
- /// Describes the basic user/group/perm tuplet for a file or folder
- /// </summary>
- public struct FileInfo
- {
- public readonly long UID;
- public readonly long GID;
- public readonly long Permissions;
- public readonly string OwnerName;
- public readonly string GroupName;
-
- internal FileInfo(Mono.Unix.UnixFileSystemInfo fse)
- {
- UID = fse.OwnerUserId;
- GID = fse.OwnerGroupId;
- Permissions = (long)fse.FileAccessPermissions;
-
- try
- {
- OwnerName = fse.OwnerUser.UserName;
- }
- catch (ArgumentException)
- {
- // Could not retrieve user name, possibly the user is not defined on the local system
- OwnerName = null;
- }
-
- try
- {
- GroupName = fse.OwnerGroup.GroupName;
- }
- catch (ArgumentException)
- {
- // Could not retrieve group name, possibly the group is not defined on the local system
- GroupName = null;
- }
- }
- }
-
- /// <summary>
- /// Gets the basic user/group/perm tuplet for a file or folder
- /// </summary>
- /// <returns>The basic user/group/perm tuplet for a file or folder</returns>
- /// <param name="path">The full path to look up</param>
- public static FileInfo GetUserGroupAndPermissions(string path)
- {
- return new FileInfo(Mono.Unix.UnixFileInfo.GetFileSystemEntry(path));
- }
-
- /// <summary>
- /// Sets the basic user/group/perm tuplet for a file or folder
- /// </summary>
- /// <param name="path">The full path to look up</param>
- /// <param name="uid">The owner user id to set</param>
- /// <param name="gid">The owner group id to set</param>
- /// <param name="permissions">The file access permissions to set</param>
- public static void SetUserGroupAndPermissions(string path, long uid, long gid, long permissions)
- {
- Mono.Unix.UnixFileInfo.GetFileSystemEntry(path).SetOwner(uid, gid);
- Mono.Unix.UnixFileInfo.GetFileSystemEntry(path).FileAccessPermissions = (Mono.Unix.FileAccessPermissions)permissions;
- }
-
- /// <summary>
- /// Gets the UID from a user name
- /// </summary>
- /// <returns>The user ID.</returns>
- /// <param name="name">The user name.</param>
- public static long GetUserID(string name)
- {
- return new Mono.Unix.UnixUserInfo(name).UserId;
- }
-
- /// <summary>
- /// Gets the GID from a group name
- /// </summary>
- /// <returns>The user ID.</returns>
- /// <param name="name">The group name.</param>
- public static long GetGroupID(string name)
- {
- return new Mono.Unix.UnixGroupInfo(name).GroupId;
- }
-
- /// <summary>
- /// Gets the number of hard links for a file
- /// </summary>
- /// <returns>The hardlink count</returns>
- /// <param name="path">The full path to look up</param>
- public static long GetHardlinkCount(string path)
- {
- var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
- if (fse.IsRegularFile || fse.IsDirectory)
- return fse.LinkCount;
- else
- return 0;
- }
-
- /// <summary>
- /// Gets a unique ID for the path inode target,
- /// which is the device ID and inode ID
- /// joined with a &quot;:&quot;
- /// </summary>
- /// <returns>The inode target ID.</returns>
- /// <param name="path">The full path to look up</param>
- public static string GetInodeTargetID(string path)
- {
- var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
- return fse.Device + ":" + fse.Inode;
- }
- }
-}
-
+using System;
+using System.Collections.Generic;
+using Mono.Unix.Native;
+
+namespace UnixSupport
+{
+ public static class File
+ {
+
+ private static readonly bool SUPPORTS_LLISTXATTR;
+
+ static File ()
+ {
+ bool works = false;
+ try
+ {
+ string[] v;
+ Mono.Unix.Native.Syscall.llistxattr("/", out v);
+ works = true;
+ }
+ catch (EntryPointNotFoundException e)
+ {
+ }
+ catch
+ {
+ }
+ SUPPORTS_LLISTXATTR = works;
+ }
+
+ /// <summary>
+ /// Opens the file and honors advisory locking.
+ /// </summary>
+ /// <returns>A open stream that references the file</returns>
+ /// <param name="path">The full path to the file</param>
+ public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode)
+ {
+ return OpenExclusive(path, mode, (int)Mono.Unix.Native.FilePermissions.DEFFILEMODE);
+ }
+
+ /// <summary>
+ /// Opens the file and honors advisory locking.
+ /// </summary>
+ /// <returns>A open stream that references the file</returns>
+ /// <param name="path">The full path to the file</param>
+ /// <param name="filemode">The file create mode</param>
+ public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode, int filemode)
+ {
+ Flock lck;
+ lck.l_len = 0;
+ lck.l_pid = Syscall.getpid();
+ lck.l_start = 0;
+ lck.l_type = LockType.F_WRLCK;
+ lck.l_whence = SeekFlags.SEEK_SET;
+
+ OpenFlags flags = OpenFlags.O_CREAT;
+ if (mode == System.IO.FileAccess.Read)
+ {
+ lck.l_type = LockType.F_RDLCK;
+ flags |= OpenFlags.O_RDONLY;
+ } else if (mode == System.IO.FileAccess.Write) {
+ flags |= OpenFlags.O_WRONLY;
+ } else {
+ flags |= OpenFlags.O_RDWR;
+ }
+
+ int fd = Syscall.open(path, flags, (Mono.Unix.Native.FilePermissions)filemode);
+ if (fd > 0)
+ {
+ //This does not work on OSX, it gives ENOTTY
+ //int res = Syscall.fcntl(fd, Mono.Unix.Native.FcntlCommand.F_SETLK, ref lck);
+
+ //This is the same (at least for our purpose, and works on OSX)
+ int res = Syscall.lockf(fd, LockfCommand.F_TLOCK, 0);
+
+ //If we have the lock, return the stream
+ if (res == 0)
+ return new Mono.Unix.UnixStream(fd);
+ else
+ {
+ Mono.Unix.Native.Syscall.close(fd);
+ throw new LockedFileException(path, mode);
+ }
+ }
+
+ throw new BadFileException(path);
+ }
+
+ [Serializable]
+ private class BadFileException : System.IO.IOException
+ {
+ public BadFileException(string filename)
+ : base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError()))
+ {
+ }
+ }
+
+ [Serializable]
+ private class LockedFileException : System.IO.IOException
+ {
+ public LockedFileException(string filename, System.IO.FileAccess mode)
+ : base(string.Format("Unable to open the file \"{0}\" in mode {1}, error: {2} ({3})", filename, mode, Syscall.GetLastError(), (int)Syscall.GetLastError()))
+ {
+ }
+ }
+
+ [Serializable]
+ private class FileAccesException : System.IO.IOException
+ {
+ public FileAccesException(string filename, string method)
+ : base(string.Format("Unable to access the file \"{0}\" with method {1}, error: {2} ({3})", filename, method, Syscall.GetLastError(), (int)Syscall.GetLastError()))
+ {
+ }
+ }
+
+ /// <summary>
+ /// Gets the symlink target for the given path
+ /// </summary>
+ /// <param name="path">The path to get the symlink target for</param>
+ /// <returns>The symlink target</returns>
+ public static string GetSymlinkTarget(string path)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder(2048); //2kb, should cover utf16 * 1023 chars
+ if (Mono.Unix.Native.Syscall.readlink(path, sb, (ulong)sb.Capacity) >= 0)
+ return sb.ToString();
+
+ throw new System.IO.FileLoadException(string.Format("Unable to get symlink for \"{0}\", error: {1} ({2})", path, Syscall.GetLastError(), (int)Syscall.GetLastError()));
+ }
+
+ /// <summary>
+ /// Creates a new symlink
+ /// </summary>
+ /// <param name="path">The path to create the symbolic link entry</param>
+ /// <param name="target">The path the symbolic link points to</param>
+ public static void CreateSymlink(string path, string target)
+ {
+ if (Mono.Unix.Native.Syscall.symlink(target, path) != 0)
+ throw new System.IO.IOException(string.Format("Unable to create symlink from \"{0}\" to \"{1}\", error: {2} ({3})", path, target, Syscall.GetLastError(), (int)Syscall.GetLastError()));
+ }
+
+ /// <summary>
+ /// Enum that describes the different filesystem entry types
+ /// </summary>
+ public enum FileType
+ {
+ File,
+ Directory,
+ Symlink,
+ Fifo,
+ Socket,
+ CharacterDevice,
+ BlockDevice,
+ Unknown
+ }
+
+ /// <summary>
+ /// Gets the type of the file.
+ /// </summary>
+ /// <returns>The file type</returns>
+ /// <param name="path">The full path to look up</param>
+ public static FileType GetFileType(string path)
+ {
+
+ var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
+ if (fse.IsRegularFile)
+ return FileType.File;
+ else if (fse.IsDirectory)
+ return FileType.Directory;
+ else if (fse.IsSymbolicLink)
+ return FileType.Symlink;
+ else if (fse.IsFifo)
+ return FileType.Fifo;
+ else if (fse.IsSocket)
+ return FileType.Socket;
+ else if (fse.IsCharacterDevice)
+ return FileType.CharacterDevice;
+ else if (fse.IsBlockDevice)
+ return FileType.CharacterDevice;
+ else
+ return FileType.Unknown;
+ }
+
+
+ /// <summary>
+ /// Gets the extended attributes.
+ /// </summary>
+ /// <returns>The extended attributes.</returns>
+ /// <param name="path">The full path to look up</param>
+ /// <param name="isSymlink">A flag indicating if the target is a symlink</param>
+ /// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
+ public static Dictionary<string, byte[]> GetExtendedAttributes(string path, bool isSymlink, bool followSymlink)
+ {
+ // If we get a symlink that we should not follow, we need llistxattr support
+ if (isSymlink && !followSymlink && !SUPPORTS_LLISTXATTR)
+ return null;
+
+ var use_llistxattr = SUPPORTS_LLISTXATTR && !followSymlink;
+
+ string[] values;
+ var size = use_llistxattr ? Mono.Unix.Native.Syscall.llistxattr(path, out values) : Mono.Unix.Native.Syscall.listxattr(path, out values);
+ if (size < 0)
+ {
+ // In case the underlying filesystem does not support extended attributes,
+ // we simply return that there are no attributes
+ if (Syscall.GetLastError() == Errno.EOPNOTSUPP)
+ return null;
+
+ throw new FileAccesException(path, use_llistxattr ? "llistxattr" : "listxattr");
+ }
+
+ var dict = new Dictionary<string, byte[]>();
+ foreach(var s in values)
+ {
+ byte[] v;
+ var n = SUPPORTS_LLISTXATTR ? Mono.Unix.Native.Syscall.lgetxattr(path, s, out v) : Mono.Unix.Native.Syscall.getxattr(path, s, out v);
+ if (n > 0)
+ dict.Add(s, v);
+ }
+
+ return dict;
+ }
+
+ /// <summary>
+ /// Sets an extended attribute.
+ /// </summary>
+ /// <param name="path">The full path to set the values for</param>
+ /// <param name="key">The extended attribute key</param>
+ /// <param name="value">The value to set</param>
+ public static void SetExtendedAttribute(string path, string key, byte[] value)
+ {
+ Mono.Unix.Native.Syscall.setxattr(path, key, value);
+ }
+
+ /// <summary>
+ /// Describes the basic user/group/perm tuplet for a file or folder
+ /// </summary>
+ public struct FileInfo
+ {
+ public readonly long UID;
+ public readonly long GID;
+ public readonly long Permissions;
+ public readonly string OwnerName;
+ public readonly string GroupName;
+
+ internal FileInfo(Mono.Unix.UnixFileSystemInfo fse)
+ {
+ UID = fse.OwnerUserId;
+ GID = fse.OwnerGroupId;
+ Permissions = (long)fse.FileAccessPermissions;
+
+ try
+ {
+ OwnerName = fse.OwnerUser.UserName;
+ }
+ catch (ArgumentException)
+ {
+ // Could not retrieve user name, possibly the user is not defined on the local system
+ OwnerName = null;
+ }
+
+ try
+ {
+ GroupName = fse.OwnerGroup.GroupName;
+ }
+ catch (ArgumentException)
+ {
+ // Could not retrieve group name, possibly the group is not defined on the local system
+ GroupName = null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the basic user/group/perm tuplet for a file or folder
+ /// </summary>
+ /// <returns>The basic user/group/perm tuplet for a file or folder</returns>
+ /// <param name="path">The full path to look up</param>
+ public static FileInfo GetUserGroupAndPermissions(string path)
+ {
+ return new FileInfo(Mono.Unix.UnixFileInfo.GetFileSystemEntry(path));
+ }
+
+ /// <summary>
+ /// Sets the basic user/group/perm tuplet for a file or folder
+ /// </summary>
+ /// <param name="path">The full path to look up</param>
+ /// <param name="uid">The owner user id to set</param>
+ /// <param name="gid">The owner group id to set</param>
+ /// <param name="permissions">The file access permissions to set</param>
+ public static void SetUserGroupAndPermissions(string path, long uid, long gid, long permissions)
+ {
+ Mono.Unix.UnixFileInfo.GetFileSystemEntry(path).SetOwner(uid, gid);
+ Mono.Unix.UnixFileInfo.GetFileSystemEntry(path).FileAccessPermissions = (Mono.Unix.FileAccessPermissions)permissions;
+ }
+
+ /// <summary>
+ /// Gets the UID from a user name
+ /// </summary>
+ /// <returns>The user ID.</returns>
+ /// <param name="name">The user name.</param>
+ public static long GetUserID(string name)
+ {
+ return new Mono.Unix.UnixUserInfo(name).UserId;
+ }
+
+ /// <summary>
+ /// Gets the GID from a group name
+ /// </summary>
+ /// <returns>The user ID.</returns>
+ /// <param name="name">The group name.</param>
+ public static long GetGroupID(string name)
+ {
+ return new Mono.Unix.UnixGroupInfo(name).GroupId;
+ }
+
+ /// <summary>
+ /// Gets the number of hard links for a file
+ /// </summary>
+ /// <returns>The hardlink count</returns>
+ /// <param name="path">The full path to look up</param>
+ public static long GetHardlinkCount(string path)
+ {
+ var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
+ if (fse.IsRegularFile || fse.IsDirectory)
+ return fse.LinkCount;
+ else
+ return 0;
+ }
+
+ /// <summary>
+ /// Gets a unique ID for the path inode target,
+ /// which is the device ID and inode ID
+ /// joined with a &quot;:&quot;
+ /// </summary>
+ /// <returns>The inode target ID.</returns>
+ /// <param name="path">The full path to look up</param>
+ public static string GetInodeTargetID(string path)
+ {
+ var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
+ return fse.Device + ":" + fse.Inode;
+ }
+ }
+}
+
diff --git a/thirdparty/UnixSupport/UnixSupport.dll b/thirdparty/UnixSupport/UnixSupport.dll
index 12ff4d9e9..5a48244d8 100755
--- a/thirdparty/UnixSupport/UnixSupport.dll
+++ b/thirdparty/UnixSupport/UnixSupport.dll
Binary files differ