How do I convert a structure that contains an array to a byte array in C#?
There was a question here about a struct without array.
But if the struct contains an array like this:
public struct DiObject
{
public byte Command;
public byte ErrorClass;
public byte Reserved;
public byte Flags;
}
public struct MyPacket
{
public uint ProtocolIdentifier;
public uint NumDi;
public DiObject[] Di;
}
It results with an access violation exception when converting the struct in a byte:
private static byte[] GetBytes(MyPacket packet, int packetSize)
{
var data = new byte[packetSize];
var ptr = Marshal.AllocHGlobal(packetSize);
// ==== Access violation exception occurs here ====
Marshal.StructureToPtr(packet, ptr, true);
Marshal.Copy(ptr, data, 0, packetSize);
Marshal.FreeHGlobal(ptr);
return data;
}
My goal is to send a message in bytes in a message queue with MSMQ.
Here the complete code that compiles and reproduce the problem.
using System;
//using System.IO;
//using System.Messaging;
using System.Runtime.InteropServices;
namespace StructToBytes
{
// 4 bytes
[Serializable]
public struct DiObject
{
public byte Command;
public byte ErrorClass;
public byte Reserved;
public byte Flags;
}
// 8 + (numDi*4) bytes
[Serializable]
public struct MyPacket
{
public uint ProtocolIdentifier;
public uint NumDi;
public DiObject[] Di;
}
internal class Program
{
private static byte[] GetBytes(MyPacket packet, int packetSize)
{
var data = new byte[packetSize];
var ptr = Marshal.AllocHGlobal(packetSize);
// ==== Access violation exception occurs here ====
Marshal.StructureToPtr(packet, ptr, true);
Marshal.Copy(ptr, data, 0, packetSize);
Marshal.FreeHGlobal(ptr);
return data;
}
private static MyPacket FromBytes(byte[] data)
{
var packet = new MyPacket();
var dataSize = Marshal.SizeOf(packet);
var ptr = Marshal.AllocHGlobal(dataSize);
Marshal.Copy(data, 0, ptr, dataSize);
packet = (MyPacket) Marshal.PtrToStructure(ptr, packet.GetType());
Marshal.FreeHGlobal(ptr);
return packet;
}
private static void Main(string[] args)
{
const string queuePath = #".\private$\test_msmq";
// Create the packet
var packet = new MyPacket();
// 8 bytes
packet.ProtocolIdentifier = 1;
packet.NumDi = 2;
// 8 bytes
packet.Di = new DiObject[packet.NumDi];
packet.Di[0].Command = 2;
packet.Di[0].ErrorClass = 3;
packet.Di[0].Flags = 4;
packet.Di[0].Reserved = 5;
packet.Di[1].Command = 6;
packet.Di[1].ErrorClass = 7;
packet.Di[1].Flags = 8;
packet.Di[1].Reserved = 9;
// Convert the struct in bytes
const int packetSize = 16;
var packetBytes = GetBytes(packet, packetSize);
// Create the message
/*
var msg = new Message();
msg.BodyStream = new MemoryStream(packetBytes);
// Open or create the message queue
if (!MessageQueue.Exists(queuePath))
MessageQueue.Create(queuePath);
// Open the queue
var q = new MessageQueue(queuePath); // {Formatter = new BinaryMessageFormatter()};
// Send the message to the queue
q.Send(msg);
*/
}
}
}
The problem lies with wrong assumption about how structure is represented in C#
// 8 + (numDi*4) bytes
[Serializable]
public struct MyPacket
{
public uint ProtocolIdentifier;
public uint NumDi;
public DiObject[] Di;
}
The assumption that size of public DiObject[] Di member is numDi * 4 is not true. In place of this field there is a pointer to the array of structures. Array is a class in .NET and is not included in place in structure declaration.
To solve this problem one can use fixed arrays. I understand that the idea behind the design is to get variable length array and it is presented in next code listing.
This code does not raise AccessViolationException during executin:
using System;
using System.IO;
using System.Messaging;
using System.Runtime.InteropServices;
namespace StructToBytes
{
// 4 bytes
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public unsafe struct DiObject
{
[FieldOffset(0)]
public byte Command;
[FieldOffset(1)]
public byte ErrorClass;
[FieldOffset(2)]
public byte Reserved;
[FieldOffset(3)]
public byte Flags;
}
// 8 + (numDi*4) bytes
[Serializable]
public unsafe struct MyPacket
{
public uint ProtocolIdentifier;
public uint NumDi;
public fixed byte Di[2 * 4];
}
internal unsafe class Program
{
private static byte[] GetBytes(MyPacket packet, int packetSize)
{
var data = new byte[packetSize];
var ptr = Marshal.AllocHGlobal(packetSize);
// ==== Access violation exception occurs here ====
Marshal.StructureToPtr(packet, ptr, true);
Marshal.Copy(ptr, data, 0, packetSize);
Marshal.FreeHGlobal(ptr);
return data;
}
private static MyPacket FromBytes(byte[] data)
{
var packet = new MyPacket();
var dataSize = Marshal.SizeOf(packet);
var ptr = Marshal.AllocHGlobal(dataSize);
Marshal.Copy(data, 0, ptr, dataSize);
packet = (MyPacket)Marshal.PtrToStructure(ptr, packet.GetType());
Marshal.FreeHGlobal(ptr);
return packet;
}
private static void Main(string[] args)
{
const string queuePath = #".\private$\test_msmq";
// Create the packet
var packet = new MyPacket();
// 8 bytes
packet.ProtocolIdentifier = 1;
packet.NumDi = 2;
// 8 bytes
// packet.Di = new DiObject[packet.NumDi];
packet.Di[0] = 2;
packet.Di[1] = 3;
packet.Di[2] = 4;
packet.Di[3] = 5;
packet.Di[4] = 6;
packet.Di[5] = 7;
packet.Di[6] = 8;
packet.Di[7] = 9;
// Convert the struct in bytes
int packetSize = Marshal.SizeOf<MyPacket>();
var packetBytes = GetBytes(packet, packetSize);
// Create the message
var msg = new Message();
msg.BodyStream = new MemoryStream(packetBytes);
// Open or create the message queue
if (!MessageQueue.Exists(queuePath))
MessageQueue.Create(queuePath);
// Open the queue
var q = new MessageQueue(queuePath); // {Formatter = new BinaryMessageFormatter()};
// Send the message to the queue
q.Send(msg);
}
}
}
Code below provides efficient conversion to byte array and from byte array for MyPacket struct with variable internal array size. Implementation avoids casts and bounds checks by using unsafe pointer arithmetic.
using System;
using System.IO;
using System.Messaging;
using System.Runtime.InteropServices;
namespace StructToBytes
{
// 4 bytes
[Serializable]
[StructLayout(LayoutKind.Explicit)]
public unsafe struct DiObject
{
[FieldOffset(0)]
public byte Command;
[FieldOffset(1)]
public byte ErrorClass;
[FieldOffset(2)]
public byte Reserved;
[FieldOffset(3)]
public byte Flags;
}
[Serializable]
public unsafe struct MyPacket
{
public uint ProtocolIdentifier;
public uint NumDi;
public DiObject[] Di;
public byte[] ToBytes()
{
byte[] buffer = new byte[NumDi];
fixed(DiObject* pDi = Di)
fixed(byte* pBuff = buffer)
{
var pBuffDi = (DiObject*)pBuff;
var pDiPtr = pDi;
for (int i = 0; i < NumDi; i++)
*pBuffDi++ = *pDiPtr++;
}
return buffer;
}
public static MyPacket Create(byte[] buffer)
{
// argument checking code here
var packet = new MyPacket();
packet.ProtocolIdentifier = buffer[0];
packet.NumDi = buffer[1];
packet.Di = new DiObject[packet.NumDi];
fixed (byte* pBuf = buffer)
fixed (DiObject* pDi = packet.Di)
{
byte* pBufPtr = pBuf;
pBufPtr += 2;
var pBufDi = (DiObject*)pBufPtr;
var pDiPtr = pDi;
for (int i = 0; i < packet.NumDi; i++)
*pDiPtr++ = *pBufDi++;
}
return packet;
}
}
internal unsafe class Program
{
private static void Main(string[] args)
{
const string queuePath = #".\private$\test_msmq";
// Create the packet
var packet = new MyPacket();
// 8 bytes
packet.ProtocolIdentifier = 1;
packet.NumDi = 5;
// 8 bytes
packet.Di = new DiObject[packet.NumDi];
packet.Di[0].Command = 2;
packet.Di[0].ErrorClass = 3;
packet.Di[0].Flags = 4;
packet.Di[0].Reserved = 5;
packet.Di[1].Command = 6;
packet.Di[1].ErrorClass = 7;
packet.Di[1].Flags = 8;
packet.Di[1].Reserved = 9;
packet.Di[2].Command = 6;
packet.Di[2].ErrorClass = 7;
packet.Di[2].Flags = 8;
packet.Di[2].Reserved = 9;
packet.Di[3].Command = 6;
packet.Di[3].ErrorClass = 7;
packet.Di[3].Flags = 8;
packet.Di[3].Reserved = 9;
// Create the message
var msg = new Message();
msg.BodyStream = new MemoryStream(packet.ToBytes());
// Open or create the message queue
if (!MessageQueue.Exists(queuePath))
MessageQueue.Create(queuePath);
// Open the queue
var q = new MessageQueue(queuePath);
// Send the message to the queue
q.Send(msg);
}
}
}
I am having the most difficult time marshaling this struct between C# and C++.
What makes it very hard to troubleshoot is that SOMETIMES the strings are populated with data (wtf), but most of the time they are not.
I've tried sending over an Array of structs as well as a IntPtr, but the results are similar, the strings in the struct are almost always empty and I can't figure out what I'm doing wrong in the marshaling. The code is posted below. Any help would be appreciated.
Edit***
Turns out the problem was on the C++ side and all the marshaling stuff was correct. Thanks for the tip Hans. ***
C++:
#pragma pack (push, 1)
typedef struct
{
char FirmwareVers[FS_MAX_FIRMWARE_VER];
char SerialNum[FS_MAX_SERIAL_NUM];
char HardwareVers[FS_MAX_HW_VER];
ULONG StatusFlags;
int LMIndex;
} FS_LMON_STATUS, *PFS_LMON_STATUS;
DllExport int _stdcall FS_GetLMs(PFS_LMON_STATUS pLaunchMonInfo, int MaxLaunchMons, int *pNumLaunchMons)
{
int Cnt;
FS_LMON_STATUS LMStatus;
if(!g_IsInitalized)
return FS_NOT_INITALIZED;
*pNumLaunchMons = 0;
if(MaxLaunchMons == 0)
return FS_ERROR;
for(Cnt = 0; Cnt < MAX_LM_CONNECTIONS; Cnt++)
{
if(g_CreatedClasses.pLMList->GetLMStatus(Cnt, &LMStatus) != FS_SUCCESS)
continue;
if(LMStatus.LMIndex != INVALID_LM_INDEX)
{
memcpy(pLaunchMonInfo, &LMStatus, sizeof(LMStatus));
pLaunchMonInfo++;
(*pNumLaunchMons)++;
MaxLaunchMons--;
if(MaxLaunchMons == 0)
{
return FS_SUCCESS;
}
}
}
return FS_SUCCESS;
}
C#:
[DllImport("FSADLL", SetLastError = false)]
private static extern int FS_GetLMs([Out] IntPtr pLaunchMonInfo, int MaxLaunchMons, ref int pNumLaunchMons);
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] //, Size = 38)]
public struct FS_LMON_STATUS
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_FIRMWARE_VER)] //10 bytes
public string FirmwareVers;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_SERIAL_NUM)] // 15 bytes
public string SerialNum;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = FS_MAX_HW_VER)] // 5 bytes
public string HardwareVers;
public uint StatusFlags; //4 bytes
public int LMIndex; // identifies which index //4 bytes
}
const int max_launch_monitors = 8;
FS_LMON_STATUS[] dev_info = new FS_LMON_STATUS[max_launch_monitors];
int num_launch_monitors = 0;
IntPtr pAddr = Marshal.AllocHGlobal(max_launch_monitors * Marshal.SizeOf(typeof(FS_LMON_STATUS)));
Marshal.StructureToPtr(dev_info, pAddr, false);
int result = FS_GetLMs(pAddr, max_launch_monitors, ref num_launch_monitors);
UnityEngine.Debug.Log("Result of FS_GetLMs: " + result);
FS_LMON_STATUS[] device_info = new FS_LMON_STATUS[max_launch_monitors];
//Marshal.Copy(pAddr, device_info, (int)0, num_launch_monitors * (int)Marshal.SizeOf(typeof(FS_LMON_STATUS)));
//Marshal.ReadIntPtr(pAddr, 0);
//device_info = (FS_LMON_STATUS[]) Marshal.PtrToStructure(Marshal.AllocHGlobal(max_launch_monitors * Marshal.SizeOf(typeof(FS_LMON_STATUS[]))), typeof(FS_LMON_STATUS[]));
if (num_launch_monitors > 0)
UnityEngine.Debug.Log("GC2 Device Found.");
else // If there is no devices found, remove the previous device from the holder variable
GC2Device = null;
for (int i = 0; i < num_launch_monitors; i++)
{
device_info[i] = (FS_LMON_STATUS)Marshal.PtrToStructure(pAddr, typeof(FS_LMON_STATUS));
pAddr = new IntPtr(Marshal.SizeOf(typeof(FS_LMON_STATUS)) + pAddr.ToInt64());
}
//*** There will only ever be 1 device in the list until the old SDK is fixed ***
for (int lm_index = 0; lm_index < num_launch_monitors; lm_index++)
{
if (device_info[lm_index].StatusFlags != LM_STATUS_DISCONNECTED)
{
UnityEngine.Debug.Log("device_info.SerialNum: " + device_info[lm_index].SerialNum);
//assign each LM to a LM data structure
LaunchMonitor logical_device = new LaunchMonitor(inst);
logical_device.mLaunchMonitorType = LaunchMonitorType.LAUNCH_MONITOR_TYPE_GC2;
logical_device.mConnectionType = ConnectionType.USB_CONNECTION;
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(device_info[lm_index]));
Marshal.StructureToPtr(device_info[lm_index], pnt, false);
//Marshal.Copy(device_info[lm_index], dv_info, 0, (uint)Marshal.SizeOf(typeof(FS_LMON_STATUS)));
logical_device.mConnectionToken = pnt;
//GC2Devices.Add(logical_device);
logical_device.Serial = logical_device.GetSerialNumber();
GC2Device = logical_device;
}
}
Turns out the problem was on the C++ side and all the marshaling stuff was correct. Thanks for the tip Hans.
Question:
In C/C++/C#. (I need it for C#, but C and C++ is also fine).
How can I do a mount -a on Linux.
I mean programmatically, without starting a process like
system("mount -a");
Edit:
Note the "-a".
My question is not actually about how to mount A mountpoint.
It's about how to mount ALL mountpoints in /etc/fstab.
That means parsing the file, extracting the mountpoints, check if already mounted, and only if not already mounted, mount...
Check out the man page by typing man 2 mount. It talks about a system call that can avoid the actual use of system():
#include <sys/mount.h>
int mount(const char *source, const char *target, const char *filesystemtype,
unsigned long mountflags, const void *data);
#Ignacio Vazquez-Abrams:
About your "no way to perform this in C#" ...
Proof that you're wrong by contradiction:
The bellow code is capable of doing the same as
(apt-get install jfsutils)
dd if=/dev/zero of=jfs.dsk bs=1048576 count=150
mkfs.jfs -O jfs.dsk
mkdir -p /mnt/jfs
mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop
umount /mnt/jfs/
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Syscalls
{
public class Linux
{
// apt-get source util-linux
// ./mount/loop.h
// ./mount/mount.c
// ./mount/lomount.c
// ./include/linux_version.h
// ./lib/linux_version.c
// ./include/linux_reboot.h
protected const int LOOP_SET_FD = 0x4C00;
protected const int LOOP_CLR_FD = 0x4C01;
protected const int LOOP_GET_STATUS = 0x4C03;
protected const int LOOP_SET_STATUS = 0x4C02;
protected const int LOOP_GET_STATUS64 = 0x4C05;
protected const int LOOP_SET_STATUS64 = 0x4C04;
protected const int LO_NAME_SIZE = 64;
protected const int LO_KEY_SIZE = 32;
protected const int PATH_MAX = 4096;
// MS_RELATIME //(default for Linux >= 2.6.30)
// MS_STRICTATIME //(default for Linux < 2.6.30)
// http://harmattan-dev.nokia.com/docs/library/html/manpages/headers/sys/mount.html
public enum MountFlags : ulong
{
MS_RDONLY = 1, // Mount read-only.
MS_NOSUID = 2, // Ignore suid and sgid bits.
MS_NODEV = 4, // Disallow access to device special files.
MS_NOEXEC = 8, // Disallow program execution.
MS_SYNCHRONOUS = 16, // Writes are synced at once.
MS_REMOUNT = 32, // Alter flags of a mounted FS.
MS_MANDLOCK = 64, // Allow mandatory locks on an FS.
S_WRITE = 128, // Write on file/directory/symlink.
S_APPEND = 256, // Append-only file.
S_IMMUTABLE = 512, // Immutable file.
MS_NOATIME = 1024, // Do not update access times.
MS_NODIRATIME = 2048, // Do not update directory access times.
MS_BIND = 4096, // Bind directory at different place.
}; // End Enum MountFlags : ulong
/*
// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/fcntl.h.html
[Flags]
protected enum OpenFlags : int
{
// open-only flags
O_RDONLY = 0x0000, // open for reading only
O_WRONLY = 0x0001, // open for writing only
O_RDWR = 0x0002, // open for reading and writing
O_ACCMODE = 0x0003, // mask for above modes
//#ifdef KERNEL
FREAD = 0x0001,
FWRITE = 0x0002,
//#endif
O_NONBLOCK = 0x0004, // no delay
O_APPEND = 0x0008, // set append mode
//#ifndef _POSIX_SOURCE
O_SHLOCK = 0x0010, // open with shared file lock
O_EXLOCK = 0x0020, // open with exclusive file lock
O_ASYNC = 0x0040, // signal pgrp when data ready
O_FSYNC = 0x0080, // synchronous writes
//#endif
O_CREAT = 0x0200, // create if nonexistant
O_TRUNC = 0x0400, // truncate to zero length
O_EXCL = 0x0800, // error if already exists
//#ifdef KERNEL
FMARK = 0x1000, // mark during gc()
FDEFER = 0x2000, // defer for next gc pass
FHASLOCK = 0x4000 // descriptor holds advisory lock
} // End Enum OpenFlags : int
*/
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
protected struct loop_info
{
public int lo_number;
public System.UIntPtr lo_device; //my_dev_t lo_device; // my_dev_t: long unsigned int
public System.UIntPtr lo_inode; //unsigned long lo_inode;
public System.UIntPtr lo_rdevice; //my_dev_t lo_rdevice;// my_dev_t: long unsigned int
public int lo_offset;
public int lo_encrypt_type;
public int lo_encrypt_key_size;
public int lo_flags;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
public string lo_name; //char lo_name[LO_NAME_SIZE];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_KEY_SIZE)]
public string lo_encrypt_key; //unsigned char lo_encrypt_key[LO_KEY_SIZE];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2)]
public System.UIntPtr[] lo_init; //unsigned long lo_init[2];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 4)]
public string reserved; //char reserved[4];
}; // End Struct loop_info
protected struct loop_info64
{
public System.UInt64 lo_device;
public System.UInt64 lo_inode;
public System.UInt64 lo_rdevice;
public System.UInt64 lo_offset;
public System.UInt64 lo_sizelimit; /* bytes, 0 == max available */
public System.UInt32 lo_number;
public System.UInt32 lo_encrypt_type;
public System.UInt32 lo_encrypt_key_size;
public System.UInt32 lo_flags;
// http://stackoverflow.com/questions/1725855/uint8-t-vs-unsigned-char
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
public string lo_file_name; // uint8_t lo_file_name[LO_NAME_SIZE];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_NAME_SIZE)]
public string lo_crypt_name; // uint8_t lo_crypt_name[LO_NAME_SIZE];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = LO_KEY_SIZE)]
public string lo_encrypt_key; // uint8_t lo_encrypt_key[LO_KEY_SIZE];
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2)]
public System.UInt64[] lo_init;
}; // End Struct loop_info64
// http://www.student.cs.uwaterloo.ca/~cs350/common/os161-src-html/kern_2include_2kern_2stat_8h.html
protected static bool S_ISBLK(int mode)
{
const uint S_IFMT = 070000;
const uint S_IFBLK = 050000;
return (((mode) & S_IFMT) == S_IFBLK);
} // End Function S_ISBLK
public static int KERNEL_VERSION()
{
Mono.Unix.Native.Utsname unameres = new Mono.Unix.Native.Utsname();
Mono.Unix.Native.Syscall.uname(out unameres);
System.Text.RegularExpressions.Match ma = System.Text.RegularExpressions.Regex.Match(unameres.release, #"(\d+).(\d+).(\d+)(-)?(\d+)?");
string strMajor = ma.Groups[1].Value;
string strMinor = ma.Groups[2].Value;
string strTiny = ma.Groups[3].Value;
string strPatchlevel = ma.Groups[5].Value;
int a = System.Convert.ToInt32(strMajor);
int b = System.Convert.ToInt32(strMinor);
int c = System.Convert.ToInt32(strTiny);
return KERNEL_VERSION(a, b, c);
} // End Function KERNEL_VERSION
//# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
public static int KERNEL_VERSION(int a, int b, int c)
{
return (((a) << 16) + ((b) << 8) + (c));
}
public static string CreateVirtualDisk(int iSize)
{
string strBaseDirectory = #"/volumes/";
string strFileName = System.Guid.NewGuid().ToString().Replace("-", "") + ".dsk";
string strFileNameAndPath = System.IO.Path.Combine(strBaseDirectory, strFileName);
using (var fs = new System.IO.FileStream(strFileNameAndPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
{
fs.SetLength(iSize);
} // End Using fs
return strFileNameAndPath;
} // End Function CreateVirtualDisk
// umount("/mnt/testdisk");
public static bool umount(string strMountPoint)
{
int status = UnsafeNativeMethods.umount(strMountPoint);
if (status == 0)
Console.WriteLine("Successfully unmounted device.");
else
Console.WriteLine("Unmount status: " + status.ToString());
if (status == 0)
return true;
return false;
} // End Function Unmount
public static string find_unused_loop_device()
{
string dev;
int fd;
Mono.Unix.Native.Stat statbuf;
loop_info loopinfo = new loop_info();
loop_info64 lo64 = new loop_info64();
for (int i = 0; i <= 7; i++)
{
dev = "/dev/loop" + i.ToString();
if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(dev, out statbuf)) == (false && S_ISBLK((int)statbuf.st_mode)))
{
if ((fd = Mono.Unix.Native.Syscall.open(dev, Mono.Unix.Native.OpenFlags.O_RDONLY)) >= 0)
{
// This block was commented out initially
if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS64, ref lo64) == 0)
{
if (Mono.Unix.Native.Syscall.GetLastError() == Mono.Unix.Native.Errno.ENXIO)
{ // probably free
Mono.Unix.Native.Syscall.close(fd);
return dev;
}
}
if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref loopinfo) != 0)
{
// http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/include/asm-generic/errno-base.h#L9
// ENXIO - No such device or address
// The device accessed by a command is physically not present,
// or the address of the device is not present
if (Mono.Unix.Native.Syscall.GetLastError() == Mono.Unix.Native.Errno.ENXIO)
{
// that means the device is most-likely free
Mono.Unix.Native.Syscall.close(fd);
return dev;
}
} // End if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref loopinfo) != 0)
Mono.Unix.Native.Syscall.close(fd);
} // End if ((fd = UnsafeNativeMethods.open(dev, OpenFlags.O_RDONLY)) >= 0)
} // End if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(dev, out statbuf)) == (false && S_ISBLK((int)statbuf.st_mode)))
} // Next i
return null;
} // End Function find_unused_loop_device
public static int set_loop(string device, string file, int offset, ref int loopro)
{
loop_info loopinfo = new loop_info();
int fd = 0, ffd = 0;
Mono.Unix.Native.OpenFlags mode;
mode = loopro != 0 ? Mono.Unix.Native.OpenFlags.O_RDONLY : Mono.Unix.Native.OpenFlags.O_RDWR;
if (
(
ffd = Mono.Unix.Native.Syscall.open(file, mode)
) < 0
&&
(
(!System.Convert.ToBoolean((int)loopro))
&&
(
Mono.Unix.Native.Syscall.GetLastError() != Mono.Unix.Native.Errno.EROFS
||
(ffd = Mono.Unix.Native.Syscall.open(file, mode = Mono.Unix.Native.OpenFlags.O_RDONLY))
< 0
)
)
) // if
{
Console.WriteLine("Error: file: " + file);
//perror_msg("%s", file);
return 1;
} // End if
if ((fd = Mono.Unix.Native.Syscall.open(device, mode)) < 0)
{
Mono.Unix.Native.Syscall.close(ffd);
Console.WriteLine("Error: device: " + device);
//perror_msg("%s", device);
return 1;
}
loopro = System.Convert.ToInt32(mode == Mono.Unix.Native.OpenFlags.O_RDONLY);
//memset(&loopinfo, 0, sizeof(loopinfo));
//safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
//strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
loopinfo.lo_name = string.IsNullOrEmpty(file) ? null : file.Substring(0, Math.Min(file.Length, LO_NAME_SIZE));
loopinfo.lo_offset = offset;
loopinfo.lo_encrypt_key_size = 0;
if (UnsafeNativeMethods.ioctl(fd, LOOP_SET_FD, ffd) < 0)
{
Console.WriteLine("ioctl: LOOP_SET_FD");
//perror_msg("ioctl: LOOP_SET_FD");
Mono.Unix.Native.Syscall.close(fd);
Mono.Unix.Native.Syscall.close(ffd);
return 1;
}
if (UnsafeNativeMethods.ioctl(fd, LOOP_SET_STATUS, ref loopinfo) < 0)
{
int ro = 0;
UnsafeNativeMethods.ioctl(fd, LOOP_CLR_FD, ref ro);
//perror_msg("ioctl: LOOP_SET_STATUS");
Console.WriteLine("ioctl: LOOP_SET_STATUS");
Mono.Unix.Native.Syscall.close(fd);
Mono.Unix.Native.Syscall.close(ffd);
return 1;
}
Mono.Unix.Native.Syscall.close(fd);
Mono.Unix.Native.Syscall.close(ffd);
return 0;
} // End Function set_loop
public static int del_loop(string device)
{
int fd;
if ((fd = Mono.Unix.Native.Syscall.open(device, Mono.Unix.Native.OpenFlags.O_RDONLY)) < 0)
{
//perror_msg("%s", device);
Console.WriteLine("Error description: " + Mono.Unix.Native.Syscall.strerror(Mono.Unix.Native.Syscall.GetLastError()));
return 0;
}
int r = 0;
if (UnsafeNativeMethods.ioctl(fd, LOOP_CLR_FD, ref r) < 0)
{
//perror_msg("ioctl: LOOP_CLR_FD");
Console.WriteLine("ioctl: LOOP_CLR_FD\nError description: " + Mono.Unix.Native.Syscall.strerror(Mono.Unix.Native.Syscall.GetLastError()));
return 0;
}
Mono.Unix.Native.Syscall.close(fd);
Console.WriteLine("Successfully closed loop-device\n");
return 1;
} // End Function del_loop
public static bool mount(string strDevice, string strMountPoint, string strFsType)
{
return mount(strDevice, strMountPoint, strFsType, MountFlags.MS_NOATIME);
}
public static bool mount(string strDevice, string strMountPoint, string strFsType, MountFlags mflags)
{
return mount(strDevice, strMountPoint, strFsType, mflags, IntPtr.Zero);
}
// http://cboard.cprogramming.com/c-programming/126630-using-sys-mount-h-mounting-usb-thumb-drive.html
// http://stackoverflow.com/questions/10458549/mount-usb-drive-in-linux-with-c
// mount("/dev/loop1", "/mnt/testdisk", "vfat");
public static bool mount(string strDevice, string strMountPoint, string strFsType, MountFlags mflags, IntPtr options)
{
// http://linux.die.net/man/2/mount
// MS_RDONLY
// MS_RELATIME (default for Linux >= 2.6.30)
// MS_STRICTATIME (default for Linux < 2.6.30)
if (UnsafeNativeMethods.mount(strDevice, strMountPoint, strFsType, mflags, options) != 0)
{
Mono.Unix.Native.Errno errno = Mono.Unix.Native.Syscall.GetLastError();
if (errno == Mono.Unix.Native.Errno.EBUSY)
{
Console.WriteLine("Mountpoint busy");
}
else
{
Console.WriteLine("Mount error: " + Mono.Unix.Native.Syscall.strerror(errno));
}
return false;
}
else
{
Console.WriteLine("Successfully mounted device !");
}
return true; ;
} // End Function mount
static class UnsafeNativeMethods
{
//string name = "Test";
//TypedReference tf = __makeref(name);
//int c = VarSum(2, __arglist(__makeref(name)));
// http://khason.net/blog/how-to-pinvoke-varargs-variable-arguments-in-c-or-hidden-junk-in-clr/
// //int rv = ioctl(2, 3, __arglist(5, 10));
[System.Runtime.InteropServices.DllImportAttribute("libc", EntryPoint = "ioctl",
CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
public static extern int ioctl(int descriptor, int request, __arglist);
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, int request, int data);
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, int request, ref int data);
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, int request, ref loop_info data);
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, int request, ref loop_info64 data);
//[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
//public static extern int open([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]string pathname, OpenFlags flags);
//[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
//public static extern int close(int fd);
//[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
//public static extern IntPtr read(int fd, IntPtr buffer, UIntPtr count);
///////unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
// http://linux.die.net/man/2/mount
// http://www.kernel.org/doc/man-pages/online/pages/man2/mount.2.html
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
private static extern int mount(string source, string target, string filesystemtype, UIntPtr mountflags, System.IntPtr data);
//int mount(const char *source, const char *target, const char *filesystemtype, ulong mountflags, const void *data);
public static int mount(string source, string target, string filesystemtype, MountFlags mountflags, System.IntPtr data)
{
System.UIntPtr p = new System.UIntPtr((ulong)mountflags);
return mount(source, target, filesystemtype, p, data);
} // End Function mount
[System.Runtime.InteropServices.DllImport("libc", SetLastError = true)]
public static extern int umount(string strMountPoint);
// extern int umount (__const char *__special_file);
} // End Class UnsafeNativeMethods
public static void TryMount()
{
const bool SUCCESS = true;
// int iReturnCode = Mono.Unix.Native.Syscall.system("mount -a");
// int iReturnCode = Mono.Unix.Native.Syscall.system("mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop");
// int iReturnCode = Mono.Unix.Native.Syscall.system("mkfs.jfs -O \"jfs.dsk\"");
string strLoopDeviceToUse = find_unused_loop_device();
string strMountPoint = "/mnt/testdisk";
int ro = 0;
set_loop(strLoopDeviceToUse, "/volumes/testdisk.dsk", 0, ref ro);
string strLoopDeviceToUse2 = find_unused_loop_device();
bool status = false;
int mountAttempts = 0;
do
{
//status = mount("/dev/sda1", "/media/usb0", "vfat", MS_MGC_VAL | MS_NOSUID, "");
status = mount(strLoopDeviceToUse, strMountPoint, "vfat", MountFlags.MS_NOATIME);
if (status != SUCCESS)
System.Threading.Thread.Sleep(1000);
mountAttempts++;
} while (status != SUCCESS && mountAttempts < 3);
} // End Sub TryMount
// In gcc or g++, to show all of the macros that are defined for a given platform:
// gcc -dM -E test.c
// or
// g++ -dM -E test.cpp
// http://manual.cream.org/index.cgi/gnu_dev_major.3
// http://www.gnu.org/software/gnulib/coverage/usr/include/sys/sysmacros.h.gcov.frameset.html
// http://en.wikipedia.org/wiki/C_data_types
protected static uint gnu_dev_major(System.UInt64 __dev)
{
return (uint)((uint)(((__dev >> 8) & 0xfff)) | ((uint)(__dev >> 32) & ~0xfff));
}
protected static uint gnu_dev_minor(System.UInt64 __dev)
{
return (uint)((uint)(__dev & 0xff) | ((uint)(__dev >> 12) & ~0xff));
}
public static string loopfile_from_sysfs(string device)
{
string res = null;
Mono.Unix.Native.Stat st;
System.IntPtr f;
//if (stat(device, &st) || !S_ISBLK(st.st_mode))
//if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(device, out st)) || !S_ISBLK((int) st.st_mode))
// return null;
Mono.Unix.Native.Syscall.stat(device, out st);
const string _PATH_SYS_DEVBLOCK = "/sys/dev/block";
string strPath = string.Format("{0}/{1}:{2}/loop/backing_file", _PATH_SYS_DEVBLOCK, gnu_dev_major(st.st_rdev), gnu_dev_minor(st.st_rdev));
f = Mono.Unix.Native.Syscall.fopen(strPath, "r");
if (f == IntPtr.Zero)
return null;
Mono.Unix.Native.Syscall.fclose(f);
res = System.IO.File.ReadAllText(strPath);
strPath = null;
return res;
} // End Function loopfile_from_sysfs
public static string loopdev_get_loopfile(string device)
{
string res = loopfile_from_sysfs(device);
if (res == null)
{
loop_info lo = new loop_info();
loop_info64 lo64 = new loop_info64();
int fd;
if ((fd = Mono.Unix.Native.Syscall.open(device, Mono.Unix.Native.OpenFlags.O_RDONLY)) < 0)
return null;
if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS64, ref lo64) == 0)
{
//lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
//lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
//res = strdup((char *) lo64.lo_file_name);
res = lo64.lo_file_name;
Console.WriteLine("LOOP_GET_STATUS64");
}
else if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref lo) == 0)
{
//lo.lo_name[LO_NAME_SIZE-2] = '*';
//lo.lo_name[LO_NAME_SIZE-1] = 0;
//res = strdup((char *) lo.lo_name);
res = lo.lo_name;
Console.WriteLine("LOOP_GET_STATUS");
}
Mono.Unix.Native.Syscall.close(fd);
} // End if (res == null)
return res;
} // End Function loopdev_get_loopfile
public static void TryUnmount()
{
/*
string strMountPoint = "/mnt/testdisk";
umount(strMountPoint);
System.Threading.Thread.Sleep(1000);
del_loop("/dev/loop2");
*/
string xxx = loopdev_get_loopfile("/dev/loop0");
Console.WriteLine("xxx: " + xxx);
}
// kernel-support:
// grep hfs /proc/filesystems
// cat /proc/partitions
// apt-get install hfsprogs
// sudo modprobe hfsplus
// dd if=/dev/zero of=hfsplus.dsk bs=1048576 count=150
// mkfs.hfsplus /volumes/hfsplus.dsk
// mkfs.hfsplus hfsplus.dsk
// apt-get install jfsutils
// dd if=/dev/zero of=jfs.dsk bs=1048576 count=150
// mkfs.jfs -O jfs.dsk
// mkdir -p /mnt/jfs
// mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop
// umount /mnt/jfs/
// mkdir -p /mnt/hfsplus
// mount -t hfsplus /volumes/hfsplus.dsk /mnt/hfsplus/ -o loop
//
} // End Class Linux
} // End Namespace Syscalls
// http://ubuntuforums.org/showthread.php?t=135113
// http://stackoverflow.com/questions/7027151/call-expect-script-in-c-process
// http://linux.die.net/man/1/expect
// http://linux.die.net/man/3/libexpect
// http://linuxcommand.org/man_pages/losetup8.html
// losetup /dev/loop0 /file
// losetup -d /dev/loop0
// http://linux.about.com/library/cmd/blcmdl8_losetup.htm
To perma-mount it in fstab, you need to get the partition uuid (blkid)
getmntent can help you read /etc/fstab (and then use the mount function in the other answers).
I'm trying to access some Ghostscript functions like so:
[DllImport(#"C:\Program Files\GPLGS\gsdll32.dll", EntryPoint = "gsapi_revision")]
public static extern int Foo(gsapi_revision_t x, int len);
public struct gsapi_revision_t
{
[MarshalAs(UnmanagedType.LPTStr)]
string product;
[MarshalAs(UnmanagedType.LPTStr)]
string copyright;
long revision;
long revisiondate;
}
public static void Main()
{
gsapi_revision_t foo = new gsapi_revision_t();
Foo(foo, Marshal.SizeOf(foo));
This corresponds with these definitions from the iapi.h header from ghostscript:
typedef struct gsapi_revision_s {
const char *product;
const char *copyright;
long revision;
long revisiondate;
} gsapi_revision_t;
GSDLLEXPORT int GSDLLAPI
gsapi_revision(gsapi_revision_t *pr, int len);
But my code is reading nothing into the string fields. If I add 'ref' to the function, it reads gibberish. However, the following code reads in the data just fine:
public struct gsapi_revision_t
{
IntPtr product;
IntPtr copyright;
long revision;
long revisiondate;
}
public static void Main()
{
gsapi_revision_t foo = new gsapi_revision_t();
IntPtr x = Marshal.AllocHGlobal(20);
for (int i = 0; i < 20; i++)
Marshal.WriteInt32(x, i, 0);
int result = Foo(x, 20);
IntPtr productNamePtr = Marshal.ReadIntPtr(x);
IntPtr copyrightPtr = Marshal.ReadIntPtr(x, 4);
long revision = Marshal.ReadInt64(x, 8);
long revisionDate = Marshal.ReadInt64(x, 12);
byte[] dest = new byte[1000];
Marshal.Copy(productNamePtr, dest, 0, 1000);
string name = Read(productNamePtr);
string copyright = Read(copyrightPtr);
}
public static string Read(IntPtr p)
{
List<byte> bits = new List<byte>();
int i = 0;
while (true)
{
byte b = Marshal.ReadByte(new IntPtr(p.ToInt64() + i));
if (b == 0)
break;
bits.Add(b);
i++;
}
return Encoding.ASCII.GetString(bits.ToArray());
}
So what am I doing wrong with marshaling?
UnmanagedType.LPTStr is platform dependent (ANSI on Win98, Unicode on NT/XP). Your C++ structure uses the char * type, so you probably want UnmanagedType.LPStr instead.
Also, a long in C# is 64 bits while a long in C++ is 32 bits. You probably want to use int in your C# code.