public static DateTime GetPreciseLastWriteTimeUtc(string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } var statOut = new Stat(); int statRet = Syscall.stat(path, out statOut); if (statRet == -1) { var errno = Syscall.GetLastError(); if (errno == Errno.ESRCH || errno == Errno.ENOTDIR || errno == Errno.ENOENT) { return(DateTime.MinValue); } UnixMarshal.ThrowExceptionForError(errno); } var result = NativeConvert.UnixEpoch.AddSeconds(statOut.st_mtime); // If this platform supports nanosecs // precision, take it into account. if (statOut.st_mtime_nsec != default(long)) { var ns = (double)statOut.st_mtime_nsec; result = result.AddSeconds(ns / 1000000000d); } return(result); }
/// <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); }
public bool Init(bool initiallyOwned) { bool result = true; #if MONO _handle = Syscall.open(_name, OpenFlags.O_CREAT | OpenFlags.O_EXCL, FilePermissions.S_IWUSR | FilePermissions.S_IRUSR); if (_handle != -1) { result = true; } else { Errno errno = Syscall.GetLastError(); if (errno != Errno.EEXIST) { throw new NativeException((int)errno); } _handle = Syscall.open(_name, OpenFlags.O_CREAT, FilePermissions.S_IWUSR | FilePermissions.S_IRUSR); if (_handle == -1) { throw new NativeException((int)Syscall.GetLastError()); } result = false; } if (initiallyOwned) { Wait(); } #endif return(result); }
private static void MakeMemoryExecutable(IntPtr pagePtr) { var mprotectResult = Syscall.mprotect(pagePtr, (ulong)PAGE_SIZE, MmapProts.PROT_EXEC | MmapProts.PROT_WRITE); if (mprotectResult != 0) { Console.WriteLine("Error: mprotect failed to make page at 0x{0} " + "address executable! Result: {1}, Errno: {2}", mprotectResult, Syscall.GetLastError()); Environment.Exit(1); } }
private static void ThrowIOErrorIfError(int res) { if (res == -1) { throw Syscall.GetLastError() switch { Errno.EIO => new IOException("Unknown IO exception occured."), Errno.ENOENT => new FileNotFoundException("The specified file was not found"), Errno.EACCES => new UnauthorizedAccessException("The caller does not have the required permission."), Errno.ENOTDIR => new DirectoryNotFoundException("The specified path is invalid."), Errno.ENAMETOOLONG => new PathTooLongException("The specified path, file name, or both exceed the system-defined maximum length."), Errno errno => new Exception($"Unknown exception occured with errno {errno}") }; } }
public bool Unlink() { lock (m_syncObject) { if (Syscall.unlink(m_name) == -1) { Errno errno = Syscall.GetLastError(); if (errno == Errno.ENOENT) { return(false); } throw new NativeException((int)errno); } return(true); } }
/// <summary> /// Gets the extended attribute. /// </summary> /// <returns>The extended attribute.</returns> /// <param name="path">Path to the file or folder.</param> /// <param name="key">Key of the extended attribute.</param> public string GetExtendedAttribute(string path, string key) { path = Path.GetFullPath(path); if (!File.Exists(path) && !Directory.Exists(path)) { throw new FileNotFoundException(string.Format("{0}: on path \"{1}\"", "No such file or directory", path), path); } #if __MonoCS__ byte[] value; long ret = Syscall.getxattr(path, prefix + key, out value); #if __COCOA__ if (ret != 0) { // On MacOS 93 means no value is found if (ret == 93) { return(null); } } #else if (ret == -1) { Errno error = Syscall.GetLastError(); if (error.ToString().Equals("ENODATA")) { return(null); } else { throw new ExtendedAttributeException(string.Format("{0}: on path \"{1}\"", Syscall.GetLastError().ToString(), path)); } } #endif if (value == null) { return(null); } else { return(Encoding.UTF8.GetString(value)); } #else throw new WrongPlatformException(); #endif }
public bool Wait(int millisecondsTimeout) { lock (typeof(FileMutex)) { if (handle == 0) { Open(); } bool result = false; ThreadStart placeLock = delegate() { // a write (exclusive) lock wl.l_type = LockType.F_WRLCK; int res = Syscall.fcntl(handle, FcntlCommand.F_SETLKW, ref wl); if (res == 0 && Syscall.GetLastError() != Errno.EAGAIN) { result = true; } }; if (millisecondsTimeout == -1) { // Console.WriteLine("waiting in the calling thread"); placeLock(); } else { // Console.WriteLine("waiting in the separate thread"); Thread t = new Thread(placeLock); t.IsBackground = true; t.Start(); if (!t.Join(millisecondsTimeout)) { //timeout t.Abort(); } } return(result); } }
internal override StorageSecurity GetSecurity(string absolutePath) { if (0 != Syscall.stat(absolutePath, out var stat)) { throw new LinuxIOException(Syscall.GetLastError()); } var uid = stat.st_uid; var uname = LinuxHelpers.GetUserName(uid); var gid = stat.st_gid; var gname = LinuxHelpers.GetGroupName(gid); var publicPermissions = LinuxHelpers.GetOtherPermissions(stat.st_mode); var userPermissions = LinuxHelpers.GetOwnerPermissions(stat.st_mode); var groupPermissions = LinuxHelpers.GetGroupPermissions(stat.st_mode); var builder = ImmutableDictionary.CreateBuilder <StorageActor, StoragePermissions>(); builder.Add(StorageActor.Public, publicPermissions); builder.Add(StorageActor.User(uname), userPermissions); builder.Add(StorageActor.Group(gname), groupPermissions); return(new StorageSecurity(builder.ToImmutable())); }
internal override void SetSecurity(string absolutePath, IStorageSecurity security) { if (0 != Syscall.stat(absolutePath, out var stat)) { throw new LinuxIOException(Syscall.GetLastError()); } var uid = stat.st_uid; var uname = LinuxHelpers.GetUserName(uid); var gid = stat.st_gid; var gname = LinuxHelpers.GetGroupName(gid); var ps = default(FilePermissions); // FIXME: emit warnings foreach (var kv in security) { var actor = kv.Key; var sp = kv.Value; switch (actor.ActorType) { case StorageActorType.Public: ps |= LinuxHelpers.FromOtherPermissions(sp); break; case StorageActorType.User when actor.Id == uname: ps |= LinuxHelpers.FromOwnerPermissions(sp); break; case StorageActorType.Group when actor.Id == gname: ps |= LinuxHelpers.FromGroupPermissions(sp); break; default: // warn break; } } if (0 != Syscall.chmod(absolutePath, ps)) { throw new LinuxIOException(Syscall.GetLastError()); } }
/// <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 var err = Syscall.GetLastError(); if (err == Errno.EOPNOTSUPP || err == Errno.ENODATA) { 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); }
private void ThrowIfFailed(int result) { if (result == -1) { var errno = Syscall.GetLastError(); throw errno switch { Errno.ENOATTR => new FileNotFoundException("The requested attribute was not found."), Errno.ENOSPC => new IOException("This file has reached the maximum amount of space for extended attributes."), Errno.EPERM => new PlatformNotSupportedException("Unable to set attribute on a read-only file or symbolic link."), Errno.E2BIG => new PlatformNotSupportedException("The target file system does not support the size of the attribute value."), Errno.ENODATA => new FileNotFoundException("The requested attribute was not found."), Errno.EOPNOTSUPP => new PlatformNotSupportedException("This filesystem is not supported."), Errno.ERANGE => new ArgumentException("Buffer was too small."), Errno.EACCES => new UnauthorizedAccessException("The caller does not have the required permission."), Errno.ENOENT => new FileNotFoundException($"The specified file was not found."), Errno.ENOTDIR => new DirectoryNotFoundException("The specified path is invalid."), Errno.ENAMETOOLONG => new PathTooLongException("The specified path, file name, or both exceed the system-defined maximum length."), _ => new Exception($"Unknown exception occured with errno {errno}") }; } }
/// <summary> /// Determines whether Extended Attributes are active on the filesystem. /// </summary> /// <param name="path">Path to be checked</param> /// <returns><c>true</c> if this instance is feature available the specified path; otherwise, <c>false</c>.</returns> public bool IsFeatureAvailable(string path) { #if __MonoCS__ if (!File.Exists(path) && !Directory.Exists(path)) { throw new ArgumentException( string.Format( "Given path \"{0}\" does not exists", path)); } byte[] value; string key = "test"; long ret = Syscall.getxattr(path, prefix + key, out value); bool retValue = true; if (ret != 0) { #if __COCOA__ // Feature not supported is errno 102 if (ret == 102) { retValue = false; } #else Errno error = Syscall.GetLastError(); if (error.ToString().Equals("EOPNOTSUPP")) { retValue = false; } #endif } return(retValue); #else throw new WrongPlatformException(); #endif }
/// <summary> /// Removes the extended attribute. /// </summary> /// <param name="path">Removes attribute from this path.</param> /// <param name="key">Key of the attribute, which should be removed.</param> public void RemoveExtendedAttribute(string path, string key) { path = Path.GetFullPath(path); if (!File.Exists(path) && !Directory.Exists(path)) { throw new FileNotFoundException(string.Format("{0}: on path \"{1}\"", "No such file or directory", path), path); } #if __MonoCS__ long ret = Syscall.removexattr(path, prefix + key); if (ret != 0) { #if !__COCOA__ Errno errno = Syscall.GetLastError(); if (errno != Errno.ENODATA) { throw new ExtendedAttributeException(string.Format("{0}: on path \"{1}\"", errno.ToString(), path)); } #endif } #else throw new WrongPlatformException(); #endif }
public ProcessInfo Start(ProcessStartInfo psi) { if (!(psi.User is UnixUserIdentifier) && psi.User != null) { throw new InvalidOperationException(); } var user_identifier = (UnixUserIdentifier)(psi.User ?? new UnixUserIdentifier((int)Syscall.getuid(), (int)Syscall.getgid())); var arguments = new string[] { Path.GetFileName(psi.Path) }.Concat(psi.Arguments).Concat(new string[] { null }).ToArray(); // instead of these, we just open /dev/null for now // this might change when we get better logging facilities //Syscall.pipe(out int stdout_read, out int stdout_write); // used to communicate stdout back to parent //Syscall.pipe(out int stderr_read, out int stderr_write); // used to communicate stderr back to parent int stdin_read = Syscall.open("/dev/null", OpenFlags.O_RDWR); int stdin_write = Syscall.open("/dev/null", OpenFlags.O_RDWR); int stdout_read = Syscall.open("/dev/null", OpenFlags.O_RDWR); int stdout_write = Syscall.open("/dev/null", OpenFlags.O_RDWR); int stderr_read = Syscall.open("/dev/null", OpenFlags.O_RDWR); int stderr_write = Syscall.open("/dev/null", OpenFlags.O_RDWR); Syscall.pipe(out int control_read, out int control_write); // used to communicate errors during process creation back to parent var stdout_w_ptr = new IntPtr(stdout_write); var stderr_w_ptr = new IntPtr(stderr_write); var control_w_ptr = new IntPtr(control_write); #pragma warning disable CS0618 // Type or member is obsolete int fork_ret = Mono.Posix.Syscall.fork(); #pragma warning restore CS0618 // Type or member is obsolete if (fork_ret == 0) // child process { int error = 0; Syscall.close(stdout_read); Syscall.close(stderr_read); Syscall.close(control_read); var control_w_stream = new UnixStream(control_write); var write_to_control = (Action <string>)(_ => control_w_stream.Write(Encoding.ASCII.GetBytes(_), 0, _.Length)); write_to_control("starting\n"); while (Syscall.dup2(stdout_write, 1) == -1) { if (Syscall.GetLastError() == Errno.EINTR) { continue; } else { write_to_control($"dup2-stdout:{(int)Syscall.GetLastError()}\n"); Syscall.exit(1); } } while (Syscall.dup2(stderr_write, 2) == -1) { if (Syscall.GetLastError() == Errno.EINTR) { continue; } else { write_to_control($"dup2-stderr:{(int)Syscall.GetLastError()}\n"); Syscall.exit(1); } } if ((error = Syscall.setgid(user_identifier.GroupId)) != 0) { write_to_control($"setgid:{(int)Syscall.GetLastError()}\n"); Syscall.exit(1); } if ((error = Syscall.setuid(user_identifier.UserId)) != 0) { write_to_control($"setuid:{(int)Syscall.GetLastError()}\n"); Syscall.exit(1); } if (psi.WorkingDirectory != "") { Syscall.chdir(psi.WorkingDirectory); } if ((error = Syscall.execv(psi.Path, arguments)) != 0) { write_to_control($"execv:{(int)Syscall.GetLastError()}\n"); Syscall.exit(1); } } if (fork_ret < 0) { throw new InvalidOperationException($"fork() returned {fork_ret}, errno: {Syscall.GetLastError()}"); } Syscall.close(stdout_write); Syscall.close(stderr_write); Syscall.close(control_write); var stdout_stream = new Mono.Unix.UnixStream(stdout_read); var stderr_stream = new Mono.Unix.UnixStream(stderr_read); var control_stream = new Mono.Unix.UnixStream(control_read); var control_sr = new StreamReader(control_stream); var starting_line = control_sr.ReadLine(); if (starting_line != "starting") { throw new Exception($"Expected starting message from control pipe, received {starting_line}"); } Processes.Add(fork_ret); return(new ProcessInfo(System.Diagnostics.Process.GetProcessById(fork_ret))); }
/// <summary> /// Connects to the socket /// </summary> public void Connect() { var res = Syscall.connect(Handle, CreateAddr()); if (res != 0) { throw new IOException($"Failed to connect socket (handle={Handle}, code={res}): {Syscall.GetLastError()}"); } }
/// <summary> /// Send the message to the socket pooling service. /// </summary> /// <param name="socket">Socket.</param> /// <param name="message">Message.</param> internal static unsafe void SendMessage( Socket socket, SockPoolMessage message) { fixed(byte *bufferPtr = &message.Buffer[0]) { var data = new[] { new Iovec { iov_base = (IntPtr)bufferPtr, iov_len = (ulong)message.Buffer.Length } }; var msghdr = new Msghdr { msg_iovlen = data.Length, msg_iov = data }; if (message.Handle != IntPtr.Zero) { msghdr.msg_control = new byte[Syscall.CMSG_SPACE(sizeof(int))]; var control = new Cmsghdr(); control.cmsg_len = msghdr.msg_controllen = msghdr.msg_control.Length; control.cmsg_level = UnixSocketProtocol.SOL_SOCKET; control.cmsg_type = UnixSocketControlMessage.SCM_RIGHTS; control.WriteToBuffer(msghdr, 0); var handleBuffer = BitConverter.GetBytes(message.Handle.ToInt32()); Buffer.BlockCopy( handleBuffer, 0, msghdr.msg_control, (int)Syscall.CMSG_SPACE(0), sizeof(int) ); } var rc = -1L; do { rc = Syscall.sendmsg(socket.Handle.ToInt32(), msghdr, 0); if (rc == -1) { throw new Exception( "Failed to send a message to the sockpool socket" + $", rc={Syscall.GetLastError()}" ); } else if (rc > 0) { data[0].iov_base += (int)rc; data[0].iov_len -= (ulong)rc; // Reach the end of the buffer if (data[0].iov_len == 0) { break; } } }while(rc != 0); } }
public bool SetFileProperties(ZipEntry zipEntry, string extractedFilePath, bool throwOnNativeExceptions = true) { var entry = zipEntry as UnixZipEntry; if (entry == null) { throw new ArgumentException("Invalid entry type, expected UnixZipEntry", nameof(zipEntry)); } if (String.IsNullOrEmpty(extractedFilePath)) { throw new ArgumentException("must not be null or empty", nameof(extractedFilePath)); } int err = Syscall.chmod(extractedFilePath, entry.FilePermissions); if (throwOnNativeExceptions && err < 0) { UnixMarshal.ThrowExceptionForLastError(); } Timeval modtime = Utilities.TimevalFromDateTime(entry.ModificationTime); Timeval acctime; if (entry.AccessTime != DateTime.MinValue) { acctime = Utilities.TimevalFromDateTime(entry.AccessTime); } else { acctime = modtime; } err = Syscall.utimes(extractedFilePath, new [] { acctime, modtime }); if (throwOnNativeExceptions && err < 0) { UnixMarshal.ThrowExceptionForLastError(); } // Non-critical // // Both IDs in the entry are ulong values to be "forward compatible" (whatever that means) // since the ZIP field that stores them allows for arbitrary length of the ID (which today // would really mean just 64-bit values). The casts below are thus slightly unsafer, but I // don't really think it matters that much... // uint uid = entry.UID.HasValue ? (uint)entry.UID : unchecked ((uint)-1); uint gid = entry.GID.HasValue ? (uint)entry.GID : unchecked ((uint)-1); if (Syscall.chown(extractedFilePath, uid, gid) < 0) { // TODO: log it properly var archive = entry.Archive as UnixZipArchive; if (archive.UnixOptions.VerboseLogging) { Console.WriteLine($"Warning: failed to set owner of entry '{extractedFilePath}' ({Stdlib.GetLastError ()}): {Syscall.strerror (Syscall.GetLastError ())}"); } } return(true); }
public static string GetLastErrorMessage() { return(Syscall.strerror(Syscall.GetLastError())); }
/// <summary> /// Binds the socket /// </summary> public void Bind() { var addr = CreateAddr(); var res = Syscall.bind(Handle, addr); if (res != 0) { throw new IOException($"Failed to bind socket (handle={Handle}, code={res}): {Syscall.GetLastError()}"); } // Remove the file, if it exists if (!Hidden) { Syscall.unlink(Path); } }
void OpenFile() { this.sourceFd = Syscall.open(file, OpenFlags.O_RDONLY, FilePermissions.ACCESSPERMS); if (sourceFd == -1) { completed = true; Console.Error.WriteLine("Error sending file '{0}' error: '{1}'", file, Syscall.GetLastError()); } else { Stat stat; var r = Syscall.fstat(sourceFd, out stat); if (r == -1) { completed = true; } else { length = stat.st_size; target.ResumeWriting(); } } }
/// <summary> /// Listens /// </summary> /// <param name="backlog">The backlog</param> public void Listen(int backlog = 1) { var res = Syscall.listen(Handle, backlog); if (res != 0) { throw new IOException($"Failed to listen on socket (handle={Handle}, code={res}): {Syscall.GetLastError()}"); } }
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> /// Sets the extended attribute. /// </summary> /// <param name="path">Path to the file or folder.</param> /// <param name="key">Key of the extended attribute.</param> /// <param name="value">Value of the extended attribute.</param> /// <param name="restoreLastModificationDate">If set to <c>true</c> restore last modification date.</param> public void SetExtendedAttribute(string path, string key, string value, bool restoreLastModificationDate = false) { #if __MonoCS__ path = Path.GetFullPath(path); if (!File.Exists(path) && !Directory.Exists(path)) { throw new FileNotFoundException(string.Format("{0}: on path \"{1}\"", "No such file or directory", path), path); } long ret; if (value == null) { RemoveExtendedAttribute(path, key); return; } else { ret = Syscall.setxattr(path, prefix + key, Encoding.UTF8.GetBytes(value)); } if (ret != 0) { throw new ExtendedAttributeException(string.Format("{0}: on path \"{1}\"", Syscall.GetLastError().ToString(), path)); } #else throw new WrongPlatformException(); #endif }
/// <summary> /// Reads from the event file /// </summary> /// <returns>The counter</returns> public ulong Read() { var res = Syscall.read(Handle, m_bufferHandle.Address, (ulong)m_buffer.Length); if (res != m_buffer.Length) { throw new IOException($"Failed to read {m_buffer.Length} bytes, read {res}: {Syscall.GetLastError()}"); } return(BitConverter.ToUInt64(m_buffer, 0)); }
/// <summary> /// Sends a write signal /// </summary> /// <param name="count">The counter to add</param> public void Write(ulong count) { Array.Copy(BitConverter.GetBytes(count), m_buffer, m_buffer.Length); var res = Syscall.write(Handle, m_bufferHandle.Address, (ulong)m_buffer.Length); if (res != m_buffer.Length) { throw new IOException($"Failed to write {m_buffer.Length} bytes, wrote {res}: {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())); } }
public BadFileException(string filename) : base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError())) { }
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())) { }