diff --git a/proprietary/DiskImage/Disk/Mac.cs b/proprietary/DiskImage/Disk/Mac.cs index b96994926..4078d7022 100644 --- a/proprietary/DiskImage/Disk/Mac.cs +++ b/proprietary/DiskImage/Disk/Mac.cs @@ -193,7 +193,8 @@ namespace Duplicati.Proprietary.DiskImage.Disk if (m_fileDescriptor < 0) { int errorCode = Marshal.GetLastWin32Error(); - Duplicati.Library.Logging.Log.WriteErrorMessage(LOGTAG, "initialize", null, $"Failed to open device {m_devicePath}: errno {errorCode}"); + string errorMessage = GetErrnoMessage(errorCode); + Duplicati.Library.Logging.Log.WriteErrorMessage(LOGTAG, "initialize", null, $"Failed to open device {m_devicePath}: {errorMessage} (errno: {errorCode})"); return Task.FromResult(false); } @@ -251,7 +252,8 @@ namespace Duplicati.Proprietary.DiskImage.Disk if (fcntl(m_fileDescriptor, F_FULLFSYNC, 0) < 0) { int errorCode = Marshal.GetLastWin32Error(); - Duplicati.Library.Logging.Log.WriteWarningMessage(LOGTAG, "dispose", null, $"Failed to flush data: errno {errorCode}"); + string errorMessage = GetErrnoMessage(errorCode); + Duplicati.Library.Logging.Log.WriteWarningMessage(LOGTAG, "dispose", null, $"Failed to flush data: {errorMessage} (errno: {errorCode})"); } } @@ -337,7 +339,8 @@ namespace Duplicati.Proprietary.DiskImage.Disk if (bytesRead.ToInt64() < 0) { int errorCode = Marshal.GetLastWin32Error(); - throw new IOException($"Failed to read from disk at offset {offset + totalBytesRead}: errno {errorCode}"); + string errorMessage = GetErrnoMessage(errorCode); + throw new IOException($"Failed to read from disk at offset {offset + totalBytesRead}: {errorMessage} (errno: {errorCode})"); } if (bytesRead.ToInt64() == 0) { @@ -416,7 +419,8 @@ namespace Duplicati.Proprietary.DiskImage.Disk if (bytesRead.ToInt64() < 0) { int errorCode = Marshal.GetLastWin32Error(); - throw new IOException($"Failed to read existing data for padding at offset {offset}: errno {errorCode}"); + string errorMessage = GetErrnoMessage(errorCode); + throw new IOException($"Failed to read existing data for padding at offset {offset}: {errorMessage} (errno: {errorCode})"); } } } @@ -442,12 +446,13 @@ namespace Duplicati.Proprietary.DiskImage.Disk if (bytesWritten.ToInt64() < 0) { int errorCode = Marshal.GetLastWin32Error(); + string errorMessage = GetErrnoMessage(errorCode); string hint = errorCode == 13 // EACCES ? "The disk may be mounted or you don't have sufficient permissions. Try unmounting the disk before writing." : errorCode == 30 // EROFS ? "The disk is read-only." : "Check the error code for more details."; - throw new IOException($"Failed to write to disk at offset {offset + totalBytesWritten}: errno {errorCode}. {hint}"); + throw new IOException($"Failed to write to disk at offset {offset + totalBytesWritten}: {errorMessage} (errno: {errorCode}). {hint}"); } totalBytesWritten += (int)bytesWritten.ToInt64(); } @@ -492,8 +497,31 @@ namespace Duplicati.Proprietary.DiskImage.Disk private static extern unsafe IntPtr pread(int fd, byte* buf, IntPtr count, long offset); [DllImport("libc", SetLastError = true)] - private static extern unsafe IntPtr pwrite(int fd, byte* buf, IntPtr count, long offset); + private static extern IntPtr strerror(int errnum); #endregion + + /// + /// Gets the error message corresponding to the specified errno value. + /// + /// The error number. + /// A string describing the error. + private static string GetErrnoMessage(int errno) + { + try + { + IntPtr msgPtr = strerror(errno); + var result = msgPtr != IntPtr.Zero + ? Marshal.PtrToStringUTF8(msgPtr) ?? $"Unknown error (errno: {errno})" + : $"Unknown error (errno: {errno})"; + + Console.WriteLine($"strerror({errno}) returned: {result}"); + return result; + } + catch + { + return $"Unknown error (errno: {errno})"; + } + } } }