Пример #1
0
        /// <summary>Reads the contents of a symbolic link</summary>
        /// <param name="path">Path to the symbolic link</param>
        /// <returns>Contents of the symbolic link</returns>
        internal static string ReadLink(string path)
        {
            IntPtr buf = Marshal.AllocHGlobal(4096);
            int    resultSize;

            if (DetectOS.Is64Bit)
            {
                long result64 = Extern.readlink64(path, buf, 4096);

                if (result64 <= 0)
                {
                    return(null);
                }

                resultSize = (int)result64;
            }
            else
            {
                int result = Extern.readlink(path, buf, 4096);

                if (result <= 0)
                {
                    return(null);
                }

                resultSize = result;
            }

            byte[] resultString = new byte[resultSize];
            Marshal.Copy(buf, resultString, 0, resultSize);
            Marshal.FreeHGlobal(buf);

            return(Encoding.ASCII.GetString(resultString));
        }
Пример #2
0
        internal static int ReOpen(string devicePath, int fd, out object newFd)
        {
            newFd = -1;

            int ret = Extern.close(fd);

            if (ret < 0)
            {
                return(Marshal.GetLastWin32Error());
            }

            newFd = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);

            if ((int)newFd >= 0)
            {
                return(0);
            }

            int error = Marshal.GetLastWin32Error();

            if (error != 13 &&
                error != 30)
            {
                return(Marshal.GetLastWin32Error());
            }

            newFd = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);

            return((int)newFd < 0 ? Marshal.GetLastWin32Error() : 0);
        }
Пример #3
0
        /// <summary>Sends a MMC/SD command</summary>
        /// <returns>The result of the command.</returns>
        /// <param name="fd">File handle</param>
        /// <param name="command">MMC/SD opcode</param>
        /// <param name="buffer">Buffer for MMC/SD command response</param>
        /// <param name="timeout">Timeout in seconds</param>
        /// <param name="duration">Time it took to execute the command in milliseconds</param>
        /// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
        /// <param name="write"><c>True</c> if data is sent from host to card</param>
        /// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
        /// <param name="flags">Flags indicating kind and place of response</param>
        /// <param name="blocks">How many blocks to transfer</param>
        /// <param name="argument">Command argument</param>
        /// <param name="response">Response registers</param>
        /// <param name="blockSize">Size of block in bytes</param>
        internal static int SendMmcCommand(int fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags,
                                           uint argument, uint blockSize, uint blocks, ref byte[] buffer,
                                           out uint[] response, out double duration, out bool sense, uint timeout = 0)
        {
            response = null;
            duration = 0;
            sense    = false;

            if (buffer == null)
            {
                return(-1);
            }

            var ioCmd = new MmcIocCmd();

            IntPtr bufPtr = Marshal.AllocHGlobal(buffer.Length);

            ioCmd.write_flag = write;
            ioCmd.is_ascmd   = isApplication;
            ioCmd.opcode     = (uint)command;
            ioCmd.arg        = argument;
            ioCmd.flags      = flags;
            ioCmd.blksz      = blockSize;
            ioCmd.blocks     = blocks;

            if (timeout > 0)
            {
                ioCmd.data_timeout_ns = timeout * 1000000000;
                ioCmd.cmd_timeout_ms  = timeout * 1000;
            }

            ioCmd.data_ptr = (ulong)bufPtr;

            Marshal.Copy(buffer, 0, bufPtr, buffer.Length);

            DateTime start = DateTime.UtcNow;
            int      error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd);
            DateTime end   = DateTime.UtcNow;

            sense |= error < 0;

            if (error < 0)
            {
                error = Marshal.GetLastWin32Error();
            }

            Marshal.Copy(bufPtr, buffer, 0, buffer.Length);

            response = ioCmd.response;
            duration = (end - start).TotalMilliseconds;

            Marshal.FreeHGlobal(bufPtr);

            return(error);
        }
Пример #4
0
        /// <summary>Sends a SCSI command</summary>
        /// <returns>0 if no error occurred, otherwise, errno</returns>
        /// <param name="fd">File handle</param>
        /// <param name="cdb">SCSI CDB</param>
        /// <param name="buffer">Buffer for SCSI command response</param>
        /// <param name="senseBuffer">Buffer with the SCSI sense</param>
        /// <param name="timeout">Timeout in seconds</param>
        /// <param name="direction">SCSI command transfer direction</param>
        /// <param name="duration">Time it took to execute the command in milliseconds</param>
        /// <param name="sense">
        ///     <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
        ///     sense
        /// </param>
        internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
                                            ScsiIoctlDirection direction, out double duration, out bool sense)
        {
            senseBuffer = null;
            duration    = 0;
            sense       = false;

            if (buffer == null)
            {
                return(-1);
            }

            var ioHdr = new SgIoHdrT();

            senseBuffer = new byte[32];

            ioHdr.interface_id    = 'S';
            ioHdr.cmd_len         = (byte)cdb.Length;
            ioHdr.mx_sb_len       = (byte)senseBuffer.Length;
            ioHdr.dxfer_direction = direction;
            ioHdr.dxfer_len       = (uint)buffer.Length;
            ioHdr.dxferp          = Marshal.AllocHGlobal(buffer.Length);
            ioHdr.cmdp            = Marshal.AllocHGlobal(cdb.Length);
            ioHdr.sbp             = Marshal.AllocHGlobal(senseBuffer.Length);
            ioHdr.timeout         = timeout * 1000;
            ioHdr.flags           = (uint)SgFlags.DirectIo;

            Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length);
            Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length);
            Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length);

            DateTime start = DateTime.UtcNow;
            int      error = Extern.ioctlSg(fd, LinuxIoctl.SgIo, ref ioHdr);
            DateTime end   = DateTime.UtcNow;

            if (error < 0)
            {
                error = Marshal.GetLastWin32Error();
            }

            Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length);
            Marshal.Copy(ioHdr.cmdp, cdb, 0, cdb.Length);
            Marshal.Copy(ioHdr.sbp, senseBuffer, 0, senseBuffer.Length);

            sense |= (ioHdr.info & SgInfo.OkMask) != SgInfo.Ok;

            duration = ioHdr.duration > 0 ? ioHdr.duration : (end - start).TotalMilliseconds;

            Marshal.FreeHGlobal(ioHdr.dxferp);
            Marshal.FreeHGlobal(ioHdr.cmdp);
            Marshal.FreeHGlobal(ioHdr.sbp);

            return(error);
        }
Пример #5
0
        internal static int BufferedOsRead(int fd, out byte[] buffer, long offset, uint length, out double duration)
        {
            buffer = new byte[length];

            DateTime start = DateTime.Now;

            long sense = Extern.lseek(fd, offset, SeekWhence.Begin);

            DateTime end = DateTime.Now;

            if (sense < 0)
            {
                duration = (end - start).TotalMilliseconds;

                return(Marshal.GetLastWin32Error());
            }

            sense = DetectOS.Is64Bit ? Extern.read64(fd, buffer, length) : Extern.read(fd, buffer, (int)length);

            end      = DateTime.Now;
            duration = (end - start).TotalMilliseconds;

            return(sense < 0 ? Marshal.GetLastWin32Error() : 0);
        }
Пример #6
0
        internal static int SendMultipleMmcCommands(int fd, Device.MmcSingleCommand[] commands, out double duration,
                                                    out bool sense, uint timeout = 0)
        {
            duration = 0;
            sense    = false;
            int off = 0;

            // Create array for buffers
            IntPtr[] bufferPointers = new IntPtr[commands.Length];

            // Allocate memory for the array for commands
            byte[] ioMultiCmd = new byte[sizeof(ulong) + (Marshal.SizeOf <MmcIocCmd>() * commands.Length)];

            // First value of array is uint64 with count of commands
            Array.Copy(BitConverter.GetBytes((ulong)commands.Length), 0, ioMultiCmd, 0, sizeof(ulong));

            off = sizeof(ulong);

            for (int i = 0; i < commands.Length; i++)
            {
                // Create command
                var ioCmd = new MmcIocCmd();

                // Allocate buffer
                bufferPointers[i] = Marshal.AllocHGlobal(commands[i].buffer.Length);

                // Define command
                ioCmd.write_flag = commands[i].write;
                ioCmd.is_ascmd   = commands[i].isApplication;
                ioCmd.opcode     = (uint)commands[i].command;
                ioCmd.arg        = commands[i].argument;
                ioCmd.flags      = commands[i].flags;
                ioCmd.blksz      = commands[i].blockSize;
                ioCmd.blocks     = commands[i].blocks;

                if (timeout > 0)
                {
                    ioCmd.data_timeout_ns = timeout * 1000000000;
                    ioCmd.cmd_timeout_ms  = timeout * 1000;
                }

                ioCmd.data_ptr = (ulong)bufferPointers[i];

                // Copy buffer to unmanaged space
                Marshal.Copy(commands[i].buffer, 0, bufferPointers[i], commands[i].buffer.Length);

                // Copy command to array
                byte[] ioCmdBytes = Helpers.Marshal.StructureToByteArrayLittleEndian(ioCmd);
                Array.Copy(ioCmdBytes, 0, ioMultiCmd, off, Marshal.SizeOf <MmcIocCmd>());

                // Advance pointer
                off += Marshal.SizeOf <MmcIocCmd>();
            }

            // Allocate unmanaged memory for array of commands
            IntPtr ioMultiCmdPtr = Marshal.AllocHGlobal(ioMultiCmd.Length);

            // Copy array of commands to unmanaged memory
            Marshal.Copy(ioMultiCmd, 0, ioMultiCmdPtr, ioMultiCmd.Length);

            // Send command
            DateTime start = DateTime.UtcNow;
            int      error = Extern.ioctlMmcMulti(fd, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
            DateTime end   = DateTime.UtcNow;

            sense |= error < 0;

            if (error < 0)
            {
                error = Marshal.GetLastWin32Error();
            }

            duration = (end - start).TotalMilliseconds;

            off = sizeof(ulong);

            // Copy array from unmanaged memory
            Marshal.Copy(ioMultiCmdPtr, ioMultiCmd, 0, ioMultiCmd.Length);

            // TODO: Use real pointers this is too slow
            for (int i = 0; i < commands.Length; i++)
            {
                byte[] tmp = new byte[Marshal.SizeOf <MmcIocCmd>()];

                // Copy command to managed space
                Array.Copy(ioMultiCmd, off, tmp, 0, tmp.Length);
                MmcIocCmd command = Helpers.Marshal.ByteArrayToStructureLittleEndian <MmcIocCmd>(tmp);

                // Copy response
                commands[i].response = command.response;

                // Copy buffer to managed space
                Marshal.Copy(bufferPointers[i], commands[i].buffer, 0, commands[i].buffer.Length);

                // Free buffer
                Marshal.FreeHGlobal(bufferPointers[i]);

                // Advance pointer
                off += Marshal.SizeOf <MmcIocCmd>();
            }

            // Free unmanaged memory
            Marshal.FreeHGlobal(ioMultiCmdPtr);

            return(error);
        }
Пример #7
0
        /// <summary>Gets a list of all known storage devices on Linux</summary>
        /// <returns>List of devices</returns>
        internal static DeviceInfo[] GetList()
        {
            string[] sysdevs = Directory.GetFileSystemEntries(PATH_SYS_DEVBLOCK, "*", SearchOption.TopDirectoryOnly);

            DeviceInfo[] devices = new DeviceInfo[sysdevs.Length];
            bool         hasUdev;

            IntPtr udev = IntPtr.Zero;

            try
            {
                udev    = Extern.udev_new();
                hasUdev = udev != IntPtr.Zero;
            }
            catch
            {
                hasUdev = false;
            }

            for (int i = 0; i < sysdevs.Length; i++)
            {
                devices[i] = new DeviceInfo
                {
                    Path = "/dev/" + Path.GetFileName(sysdevs[i])
                };

                if (hasUdev)
                {
                    IntPtr udevDev =
                        Extern.udev_device_new_from_subsystem_sysname(udev, "block", Path.GetFileName(sysdevs[i]));

                    devices[i].Vendor = Extern.udev_device_get_property_value(udevDev, "ID_VENDOR");
                    devices[i].Model  = Extern.udev_device_get_property_value(udevDev, "ID_MODEL");

                    if (!string.IsNullOrEmpty(devices[i].Model))
                    {
                        devices[i].Model = devices[i].Model.Replace('_', ' ');
                    }

                    devices[i].Serial = Extern.udev_device_get_property_value(udevDev, "ID_SCSI_SERIAL");

                    if (string.IsNullOrEmpty(devices[i].Serial))
                    {
                        devices[i].Serial = Extern.udev_device_get_property_value(udevDev, "ID_SERIAL_SHORT");
                    }

                    devices[i].Bus = Extern.udev_device_get_property_value(udevDev, "ID_BUS");
                }

                StreamReader sr;

                if (File.Exists(Path.Combine(sysdevs[i], "device/vendor")) &&
                    string.IsNullOrEmpty(devices[i].Vendor))
                {
                    sr = new StreamReader(Path.Combine(sysdevs[i], "device/vendor"), Encoding.ASCII);
                    devices[i].Vendor = sr.ReadLine()?.Trim();
                }
                else if (devices[i].Path.StartsWith("/dev/loop", StringComparison.CurrentCulture))
                {
                    devices[i].Vendor = "Linux";
                }

                if (File.Exists(Path.Combine(sysdevs[i], "device/model")) &&
                    (string.IsNullOrEmpty(devices[i].Model) || devices[i].Bus == "ata"))
                {
                    sr = new StreamReader(Path.Combine(sysdevs[i], "device/model"), Encoding.ASCII);
                    devices[i].Model = sr.ReadLine()?.Trim();
                }
                else if (devices[i].Path.StartsWith("/dev/loop", StringComparison.CurrentCulture))
                {
                    devices[i].Model = "Linux";
                }

                if (File.Exists(Path.Combine(sysdevs[i], "device/serial")) &&
                    string.IsNullOrEmpty(devices[i].Serial))
                {
                    sr = new StreamReader(Path.Combine(sysdevs[i], "device/serial"), Encoding.ASCII);
                    devices[i].Serial = sr.ReadLine()?.Trim();
                }

                if (string.IsNullOrEmpty(devices[i].Vendor) ||
                    devices[i].Vendor == "ATA")
                {
                    if (devices[i].Model != null)
                    {
                        string[] pieces = devices[i].Model.Split(' ');

                        if (pieces.Length > 1)
                        {
                            devices[i].Vendor = pieces[0];
                            devices[i].Model  = devices[i].Model.Substring(pieces[0].Length + 1);
                        }
                    }
                }

                // TODO: Get better device type from sysfs paths
                if (string.IsNullOrEmpty(devices[i].Bus))
                {
                    if (devices[i].Path.StartsWith("/dev/loop", StringComparison.CurrentCulture))
                    {
                        devices[i].Bus = "loop";
                    }
                    else if (devices[i].Path.StartsWith("/dev/nvme", StringComparison.CurrentCulture))
                    {
                        devices[i].Bus = "NVMe";
                    }
                    else if (devices[i].Path.StartsWith("/dev/mmc", StringComparison.CurrentCulture))
                    {
                        devices[i].Bus = "MMC/SD";
                    }
                }
                else
                {
                    devices[i].Bus = devices[i].Bus.ToUpper();
                }

                switch (devices[i].Bus)
                {
                case "ATA":
                case "ATAPI":
                case "SCSI":
                case "USB":
                case "PCMCIA":
                case "FireWire":
                case "MMC/SD":
                    devices[i].Supported = true;

                    break;
                }
            }

            return(devices);
        }