Files
duplicati/thirdparty/UnixSupport/File.cs
T

111 lines
3.8 KiB
C#
Raw Normal View History

2011-11-10 16:30:25 +00:00
using System;
2011-11-13 10:58:35 +00:00
using Mono.Unix.Native;
2011-11-10 16:30:25 +00:00
namespace UnixSupport
{
public static class File
{
/// <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>
2011-11-10 16:30:25 +00:00
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)
{
2011-11-13 10:58:35 +00:00
Flock lck;
2011-11-10 16:30:25 +00:00
lck.l_len = 0;
2011-11-13 10:58:35 +00:00
lck.l_pid = Syscall.getpid();
2011-11-10 16:30:25 +00:00
lck.l_start = 0;
2011-11-13 10:58:35 +00:00
lck.l_type = LockType.F_WRLCK;
lck.l_whence = SeekFlags.SEEK_SET;
OpenFlags flags = OpenFlags.O_CREAT;
2011-11-10 16:30:25 +00:00
if (mode == System.IO.FileAccess.Read)
{
2011-11-13 10:58:35 +00:00
lck.l_type = LockType.F_RDLCK;
flags |= OpenFlags.O_RDONLY;
2011-11-10 16:30:25 +00:00
} else if (mode == System.IO.FileAccess.Write) {
2011-11-13 10:58:35 +00:00
flags |= OpenFlags.O_WRONLY;
2011-11-10 16:30:25 +00:00
} else {
2011-11-13 10:58:35 +00:00
flags |= OpenFlags.O_RDWR;
2011-11-10 16:30:25 +00:00
}
2011-11-13 10:58:35 +00:00
int fd = Syscall.open(path, flags, (Mono.Unix.Native.FilePermissions)filemode);
2011-11-10 16:30:25 +00:00
if (fd > 0)
{
2011-11-13 10:58:35 +00:00
//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);
2011-11-10 16:30:25 +00:00
//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)
2011-11-13 10:58:35 +00:00
: base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError()))
2011-11-10 16:30:25 +00:00
{
}
}
[Serializable]
private class LockedFileException : System.IO.IOException
{
public LockedFileException(string filename, System.IO.FileAccess mode)
2011-11-13 10:58:35 +00:00
: base(string.Format("Unable to open the file \"{0}\" in mode {1}, error: {2} ({3})", filename, mode, Syscall.GetLastError(), (int)Syscall.GetLastError()))
2011-11-10 16:30:25 +00:00
{
}
}
/// <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()));
}
2011-11-10 16:30:25 +00:00
}
}