// Authors:
// Jonathan Pryor (jonpryor@vt.edu)
//
-// (C) 2004 Jonathan Pryor
+// (C) 2004-2006 Jonathan Pryor
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// be thread-safe between managed & unmanaged code.
internal class ErrorMarshal
{
- internal delegate string ErrorTranslator (Error errno);
+ internal delegate string ErrorTranslator (Native.Errno errno);
internal static readonly ErrorTranslator Translate;
{
try {
Translate = new ErrorTranslator (strerror_r);
- Translate (Error.ERANGE);
+ Translate (Native.Errno.ERANGE);
}
- catch (EntryPointNotFoundException e) {
+ catch (EntryPointNotFoundException) {
Translate = new ErrorTranslator (strerror);
}
}
- private static string strerror (Error errno)
+ private static string strerror (Native.Errno errno)
{
- return Stdlib.strerror (errno);
+ return Native.Stdlib.strerror (errno);
}
- private static string strerror_r (Error errno)
+ private static string strerror_r (Native.Errno errno)
{
StringBuilder buf = new StringBuilder (16);
int r = 0;
do {
buf.Capacity *= 2;
- r = Syscall.strerror_r (errno, buf);
- } while (r == -1 && Stdlib.GetLastError() == Error.ERANGE);
+ r = Native.Syscall.strerror_r (errno, buf);
+ } while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
if (r == -1)
return "** Unknown error code: " + ((int) errno) + "**";
{
private UnixMarshal () {}
- [Obsolete ("Use GetErrorDescription (Mono.Unix.Native.Errno)")]
- public static string GetErrorDescription (Error errno)
+ [CLSCompliant (false)]
+ public static string GetErrorDescription (Native.Errno errno)
{
return ErrorMarshal.Translate (errno);
}
- public static string GetErrorDescription (Native.Errno errno)
+ public static IntPtr AllocHeap (long size)
{
- return ErrorMarshal.Translate ((Error) (int) errno);
+ if (size < 0)
+ throw new ArgumentOutOfRangeException ("size", "< 0");
+ return Native.Stdlib.malloc ((ulong) size);
}
- public static IntPtr Alloc (long size)
+ public static IntPtr ReAllocHeap (IntPtr ptr, long size)
{
if (size < 0)
throw new ArgumentOutOfRangeException ("size", "< 0");
- return Stdlib.malloc ((ulong) size);
+ return Native.Stdlib.realloc (ptr, (ulong) size);
}
- public static IntPtr ReAlloc (IntPtr ptr, long size)
+ public static void FreeHeap (IntPtr ptr)
{
- if (size < 0)
- throw new ArgumentOutOfRangeException ("size", "< 0");
- return Stdlib.realloc (ptr, (ulong) size);
+ Native.Stdlib.free (ptr);
}
- public static void Free (IntPtr ptr)
+ public static unsafe string PtrToStringUnix (IntPtr p)
{
- Stdlib.free (ptr);
+ if (p == IntPtr.Zero)
+ return null;
+
+ int len = checked ((int) Native.Stdlib.strlen (p));
+ return new string ((sbyte*) p, 0, len, UnixEncoding.Instance);
}
public static string PtrToString (IntPtr p)
{
- // TODO: deal with character set issues. Will PtrToStringAnsi always
- // "Do The Right Thing"?
if (p == IntPtr.Zero)
return null;
- return Marshal.PtrToStringAnsi (p);
+ return PtrToString (p, UnixEncoding.Instance);
+ }
+
+ public static unsafe string PtrToString (IntPtr p, Encoding encoding)
+ {
+ if (p == IntPtr.Zero)
+ return null;
+
+ if (encoding == null)
+ throw new ArgumentNullException ("encoding");
+
+ int len = GetStringByteLength (p, encoding);
+
+ // Due to variable-length encoding schemes, GetStringByteLength() may
+ // have returned multiple "null" characters. (For example, when
+ // encoding a string into UTF-8 there will be 4 terminating nulls.)
+ // We don't want these null's to be in the returned string, so strip
+ // them off.
+ string s = new string ((sbyte*) p, 0, len, encoding);
+ len = s.Length;
+ while (len > 0 && s [len-1] == 0)
+ --len;
+ if (len == s.Length)
+ return s;
+ return s.Substring (0, len);
+ }
+
+ private static int GetStringByteLength (IntPtr p, Encoding encoding)
+ {
+ Type encodingType = encoding.GetType ();
+
+ int len = -1;
+
+ // Encodings that will always end with a single null byte
+ if (typeof(UTF8Encoding).IsAssignableFrom (encodingType) ||
+ typeof(UTF7Encoding).IsAssignableFrom (encodingType) ||
+ typeof(UnixEncoding).IsAssignableFrom (encodingType) ||
+ typeof(ASCIIEncoding).IsAssignableFrom (encodingType)) {
+ len = checked ((int) Native.Stdlib.strlen (p));
+ }
+ // Encodings that will always end with a 0x0000 16-bit word
+ else if (typeof(UnicodeEncoding).IsAssignableFrom (encodingType)) {
+ len = GetInt16BufferLength (p);
+ }
+ // Some non-public encoding, such as Latin1 or a DBCS charset.
+ // Look for a sequence of encoding.GetMaxByteCount() bytes that are all
+ // 0, which should be the terminating null.
+ // This is "iffy", since it may fail for variable-width encodings; for
+ // example, UTF8Encoding.GetMaxByteCount(1) = 4, so this would read 3
+ // bytes past the end of the string, possibly into garbage memory
+ // (which is why we special case UTF above).
+ else {
+ len = GetRandomBufferLength (p, encoding.GetMaxByteCount(1));
+ }
+
+ if (len == -1)
+ throw new NotSupportedException ("Unable to determine native string buffer length");
+ return len;
+ }
+
+ private static int GetInt16BufferLength (IntPtr p)
+ {
+ int len = 0;
+ while (Marshal.ReadInt16 (p, len*2) != 0)
+ checked {++len;}
+ return checked(len*2);
+ }
+
+ private static int GetInt32BufferLength (IntPtr p)
+ {
+ int len = 0;
+ while (Marshal.ReadInt32 (p, len*4) != 0)
+ checked {++len;}
+ return checked(len*4);
+ }
+
+ private static int GetRandomBufferLength (IntPtr p, int nullLength)
+ {
+ switch (nullLength) {
+ case 1: return checked ((int) Native.Stdlib.strlen (p));
+ case 2: return GetInt16BufferLength (p);
+ case 4: return GetInt32BufferLength (p);
+ }
+
+ int len = 0;
+ int num_null_seen = 0;
+
+ do {
+ byte b = Marshal.ReadByte (p, len++);
+ if (b == 0)
+ ++num_null_seen;
+ else
+ num_null_seen = 0;
+ } while (num_null_seen != nullLength);
+
+ return len;
}
/*
* for strings.
*/
public static string[] PtrToStringArray (IntPtr stringArray)
+ {
+ return PtrToStringArray (stringArray, UnixEncoding.Instance);
+ }
+
+ public static string[] PtrToStringArray (IntPtr stringArray, Encoding encoding)
{
if (stringArray == IntPtr.Zero)
return new string[]{};
int argc = CountStrings (stringArray);
- return PtrToStringArray (argc, stringArray);
+ return PtrToStringArray (argc, stringArray, encoding);
}
private static int CountStrings (IntPtr stringArray)
* argv[argc] = NULL, which PtrToStringArray(IntPtr) requires).
*/
public static string[] PtrToStringArray (int count, IntPtr stringArray)
+ {
+ return PtrToStringArray (count, stringArray, UnixEncoding.Instance);
+ }
+
+ public static string[] PtrToStringArray (int count, IntPtr stringArray, Encoding encoding)
{
if (count < 0)
throw new ArgumentOutOfRangeException ("count", "< 0");
+ if (encoding == null)
+ throw new ArgumentNullException ("encoding");
if (stringArray == IntPtr.Zero)
return new string[count];
string[] members = new string[count];
for (int i = 0; i < count; ++i) {
IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size);
- members[i] = PtrToString (s);
+ members[i] = PtrToString (s, encoding);
}
return members;
}
- public static IntPtr StringToAlloc (string s)
+ public static IntPtr StringToHeap (string s)
+ {
+ return StringToHeap (s, UnixEncoding.Instance);
+ }
+
+ public static IntPtr StringToHeap (string s, Encoding encoding)
{
- return StringToAlloc (s, Encoding.UTF8);
+ return StringToHeap (s, 0, s.Length, encoding);
}
- public static IntPtr StringToAlloc (string s, Encoding e)
+ public static IntPtr StringToHeap (string s, int index, int count)
{
- byte[] marshal = new byte [e.GetByteCount (s) + 1];
- if (e.GetBytes (s, 0, s.Length, marshal, 0) != (marshal.Length-1))
- throw new NotSupportedException ("e.GetBytes() doesn't equal e.GetByteCount()!");
- marshal [marshal.Length-1] = 0;
- IntPtr mem = Alloc (marshal.Length);
+ return StringToHeap (s, index, count, UnixEncoding.Instance);
+ }
+
+ public static IntPtr StringToHeap (string s, int index, int count, Encoding encoding)
+ {
+ if (s == null)
+ return IntPtr.Zero;
+
+ if (encoding == null)
+ throw new ArgumentNullException ("encoding");
+
+ int min_byte_count = encoding.GetMaxByteCount(1);
+ char[] copy = s.ToCharArray (index, count);
+ byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count];
+
+ int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0);
+
+ if (bytes_copied != (marshal.Length-min_byte_count))
+ throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
+
+ IntPtr mem = AllocHeap (marshal.Length);
if (mem == IntPtr.Zero)
- throw new OutOfMemoryException ();
+ throw new UnixIOException (Native.Errno.ENOMEM);
+
bool copied = false;
try {
Marshal.Copy (marshal, 0, mem, marshal.Length);
}
finally {
if (!copied)
- Free (mem);
+ FreeHeap (mem);
}
+
return mem;
}
public static bool ShouldRetrySyscall (int r)
{
- if (r == -1 && Stdlib.GetLastError () == Error.EINTR)
- return true;
- return false;
- }
-
- [Obsolete ("Use ShouldRetrySyscall (int, out Mono.Unix.Native.Errno")]
- public static bool ShouldRetrySyscall (int r, out Error error)
- {
- error = (Error) 0;
- if (r == -1 && (error = Stdlib.GetLastError ()) == Error.EINTR)
+ if (r == -1 && Native.Stdlib.GetLastError () == Native.Errno.EINTR)
return true;
return false;
}
- public static bool ShouldRetrySyscall (int r, out Native.Errno error)
+ [CLSCompliant (false)]
+ public static bool ShouldRetrySyscall (int r, out Native.Errno errno)
{
- error = (Native.Errno) 0;
- if (r == -1 && (error = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR)
+ errno = (Native.Errno) 0;
+ if (r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR)
return true;
return false;
}
return false;
}
- [Obsolete ("Use CreateExceptionForError (Mono.Unix.Native.Errno)")]
- internal static Exception CreateExceptionForError (Error errno)
- {
- string message = GetErrorDescription (errno);
- UnixIOException p = new UnixIOException (errno);
- switch (errno) {
- case Error.EFAULT: return new NullReferenceException (message, p);
- case Error.EINVAL: return new ArgumentException (message, p);
- case Error.EIO:
- case Error.ENOSPC:
- case Error.EROFS:
- case Error.ESPIPE:
- return new IOException (message, p);
- case Error.ENAMETOOLONG: return new PathTooLongException (message, p);
- case Error.ENOENT: return new FileNotFoundException (message, p);
- case Error.ENOEXEC: return new InvalidProgramException (message, p);
- case Error.EOVERFLOW: return new OverflowException (message, p);
- case Error.ERANGE: return new ArgumentOutOfRangeException (message);
- default: /* ignore */ break;
- }
- return p;
- }
-
internal static Exception CreateExceptionForError (Native.Errno errno)
{
string message = GetErrorDescription (errno);
UnixIOException p = new UnixIOException (errno);
+
+ // Ordering: Order alphabetically by exception first (right column),
+ // then order alphabetically by Errno value (left column) for the given
+ // exception.
switch (errno) {
- case Native.Errno.EFAULT: return new NullReferenceException (message, p);
+ case Native.Errno.EBADF:
case Native.Errno.EINVAL: return new ArgumentException (message, p);
- case Native.Errno.EIO:
- case Native.Errno.ENOSPC:
- case Native.Errno.EROFS:
- case Native.Errno.ESPIPE:
- return new IOException (message, p);
- case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p);
+
+ case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message);
+ case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p);
case Native.Errno.ENOENT: return new FileNotFoundException (message, p);
+
+ case Native.Errno.EOPNOTSUPP:
+ case Native.Errno.EPERM: return new InvalidOperationException (message, p);
+
case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p);
+
+ case Native.Errno.EIO:
+ case Native.Errno.ENOSPC:
+ case Native.Errno.ENOTEMPTY:
+ case Native.Errno.ENXIO:
+ case Native.Errno.EROFS:
+ case Native.Errno.ESPIPE: return new IOException (message, p);
+
+ case Native.Errno.EFAULT: return new NullReferenceException (message, p);
case Native.Errno.EOVERFLOW: return new OverflowException (message, p);
- case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message);
+ case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p);
+
+ case Native.Errno.EACCES:
+ case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p);
+
default: /* ignore */ break;
}
return p;
internal static Exception CreateExceptionForLastError ()
{
- return CreateExceptionForError (Stdlib.GetLastError());
- }
-
- [Obsolete ("Use ThrowExceptionForError (Mono.Unix.Native.Errno)")]
- public static void ThrowExceptionForError (Error errno)
- {
- throw CreateExceptionForError (errno);
+ return CreateExceptionForError (Native.Stdlib.GetLastError());
}
+ [CLSCompliant (false)]
public static void ThrowExceptionForError (Native.Errno errno)
{
throw CreateExceptionForError (errno);
throw CreateExceptionForLastError ();
}
- [Obsolete ("Use ThrowExceptionForErrorIf (int, Mono.Unix.Native.Errno)")]
- public static void ThrowExceptionForErrorIf (int retval, Error errno)
- {
- if (retval == -1)
- ThrowExceptionForError (errno);
- }
-
+ [CLSCompliant (false)]
public static void ThrowExceptionForErrorIf (int retval, Native.Errno errno)
{
if (retval == -1)