diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index f8a9f7d9..1c3fc4c0 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,15 @@ +2015-12-31 Natalia Portillo + + * Device/Constructor.cs: + Added support for USB on Linux. + + * Device/Variables.cs: + Added support for USB detection and metadata. + + * Linux/Extern.cs: + * Linux/Command.cs: + Added readlink(3) support, for getting symlink destinations. + 2015-12-30 Natalia Portillo * Device/Variables.cs: diff --git a/DiscImageChef.Devices/Device/Constructor.cs b/DiscImageChef.Devices/Device/Constructor.cs index 0f5cf994..73133770 100644 --- a/DiscImageChef.Devices/Device/Constructor.cs +++ b/DiscImageChef.Devices/Device/Constructor.cs @@ -102,6 +102,80 @@ namespace DiscImageChef.Devices bool scsiSense = ScsiInquiry(out inqBuf, out senseBuf); + #region USB + if(platformID == DiscImageChef.Interop.PlatformID.Linux) + { + if(devicePath.StartsWith("/dev/sd")) + { + string devPath = devicePath.Substring(5); + if(System.IO.Directory.Exists("/sys/block/" + devPath)) + { + string resolvedLink = Linux.Command.ReadLink("/sys/block/" + devPath); + resolvedLink = "/sys" + resolvedLink.Substring(2); + if(!string.IsNullOrEmpty(resolvedLink)) + { + while(resolvedLink.Contains("usb")) + { + resolvedLink = System.IO.Path.GetDirectoryName(resolvedLink); + if(System.IO.File.Exists(resolvedLink + "/descriptors") && + System.IO.File.Exists(resolvedLink + "/idProduct") && + System.IO.File.Exists(resolvedLink + "/idVendor")) + { + System.IO.FileStream usbFs; + System.IO.StreamReader usbSr; + string usbTemp; + + usbFs = new System.IO.FileStream(resolvedLink + "/descriptors", System.IO.FileMode.Open, System.IO.FileAccess.Read); + byte[] usbBuf = new byte[65536]; + int usbCount = usbFs.Read(usbBuf, 0, 65536); + usbDescriptors = new byte[usbCount]; + Array.Copy(usbBuf, 0, usbDescriptors, 0, usbCount); + usbFs.Close(); + + usbSr = new System.IO.StreamReader(resolvedLink + "/idProduct"); + usbTemp = usbSr.ReadToEnd(); + ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out usbProduct); + usbSr.Close(); + + usbSr = new System.IO.StreamReader(resolvedLink + "/idVendor"); + usbTemp = usbSr.ReadToEnd(); + ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out usbVendor); + usbSr.Close(); + + if(System.IO.File.Exists(resolvedLink + "/manufacturer")) + { + usbSr = new System.IO.StreamReader(resolvedLink + "/manufacturer"); + usbManufacturerString = usbSr.ReadToEnd().Trim(); + usbSr.Close(); + } + + if(System.IO.File.Exists(resolvedLink + "/product")) + { + usbSr = new System.IO.StreamReader(resolvedLink + "/product"); + usbProductString = usbSr.ReadToEnd().Trim(); + usbSr.Close(); + } + + if(System.IO.File.Exists(resolvedLink + "/serial")) + { + usbSr = new System.IO.StreamReader(resolvedLink + "/serial"); + usbSerialString = usbSr.ReadToEnd().Trim(); + usbSr.Close(); + } + + usb = true; + break; + } + } + } + } + } + } + // TODO: Implement for other operating systems + else + usb = false; + #endregion USB + if (!scsiSense) { Decoders.SCSI.Inquiry.SCSIInquiry? Inquiry = Decoders.SCSI.Inquiry.Decode(inqBuf); @@ -173,6 +247,24 @@ namespace DiscImageChef.Devices revision = null; serial = null; } + + if (usb) + { + if (string.IsNullOrEmpty(manufacturer)) + manufacturer = usbManufacturerString; + if (string.IsNullOrEmpty(model)) + model = usbProductString; + if (string.IsNullOrEmpty(serial)) + serial = usbSerialString; + else + { + foreach (char c in serial) + { + if(Char.IsControl(c)) + serial = usbSerialString; + } + } + } } } } diff --git a/DiscImageChef.Devices/Device/Variables.cs b/DiscImageChef.Devices/Device/Variables.cs index 6a66f306..e4fd6547 100644 --- a/DiscImageChef.Devices/Device/Variables.cs +++ b/DiscImageChef.Devices/Device/Variables.cs @@ -53,6 +53,13 @@ namespace DiscImageChef.Devices readonly string serial; readonly Decoders.SCSI.PeripheralDeviceTypes scsiType; readonly bool removable; + readonly bool usb; + readonly ushort usbVendor; + readonly ushort usbProduct; + readonly byte[] usbDescriptors; + readonly string usbManufacturerString; + readonly string usbProductString; + readonly string usbSerialString; /// /// Gets the Platform ID for this device @@ -172,6 +179,10 @@ namespace DiscImageChef.Devices } } + /// + /// Gets the device's SCSI peripheral device type + /// + /// The SCSI peripheral device type. public Decoders.SCSI.PeripheralDeviceTypes SCSIType { get @@ -180,6 +191,10 @@ namespace DiscImageChef.Devices } } + /// + /// Gets a value indicating whether this device's media is removable. + /// + /// true if this device's media is removable; otherwise, false. public bool IsRemovable { get @@ -187,6 +202,90 @@ namespace DiscImageChef.Devices return removable; } } + + /// + /// Gets a value indicating whether this device is attached via USB. + /// + /// true if this device is attached via USB; otherwise, false. + public bool IsUSB + { + get + { + return usb; + } + } + + /// + /// Gets the USB vendor ID. + /// + /// The USB vendor ID. + public ushort USBVendorID + { + get + { + return usbVendor; + } + } + + /// + /// Gets the USB product ID. + /// + /// The USB product ID. + public ushort USBProductID + { + get + { + return usbProduct; + } + } + + /// + /// Gets the USB descriptors. + /// + /// The USB descriptors. + public byte[] USBDescriptors + { + get + { + return usbDescriptors; + } + } + + /// + /// Gets the USB manufacturer string. + /// + /// The USB manufacturer string. + public string USBManufacturerString + { + get + { + return usbManufacturerString; + } + } + + /// + /// Gets the USB product string. + /// + /// The USB product string. + public string USBProductString + { + get + { + return usbProductString; + } + } + + /// + /// Gets the USB serial string. + /// + /// The USB serial string. + public string USBSerialString + { + get + { + return usbSerialString; + } + } } } diff --git a/DiscImageChef.Devices/Linux/Command.cs b/DiscImageChef.Devices/Linux/Command.cs index 085434b5..6538a5dd 100644 --- a/DiscImageChef.Devices/Linux/Command.cs +++ b/DiscImageChef.Devices/Linux/Command.cs @@ -328,6 +328,34 @@ namespace DiscImageChef.Devices.Linux return error; } + + public static string ReadLink(string path) + { + IntPtr buf = Marshal.AllocHGlobal(int.MaxValue); + int resultSize; + + if (Interop.DetectOS.Is64Bit()) + { + long result64 = Extern.readlink64(path, buf, (long)int.MaxValue); + if (result64 <= 0) + return null; + + resultSize = (int)result64; + } + else + { + int result = Extern.readlink(path, buf, int.MaxValue); + if (result <= 0) + return null; + + resultSize = result; + } + + byte[] resultString = new byte[resultSize]; + Marshal.Copy(buf, resultString, 0, resultSize); + Marshal.FreeHGlobal(buf); + return System.Text.Encoding.ASCII.GetString(resultString); + } } } diff --git a/DiscImageChef.Devices/Linux/Extern.cs b/DiscImageChef.Devices/Linux/Extern.cs index 36263ff6..ad13eedd 100644 --- a/DiscImageChef.Devices/Linux/Extern.cs +++ b/DiscImageChef.Devices/Linux/Extern.cs @@ -56,6 +56,12 @@ namespace DiscImageChef.Devices.Linux [DllImport("libc", EntryPoint="ioctl", SetLastError = true)] internal static extern int ioctlSg(int fd, LinuxIoctl request, ref sg_io_hdr_t value); + + [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true)] + internal static extern int readlink(string path, System.IntPtr buf, int bufsize); + + [DllImport("libc", CharSet = CharSet.Ansi, EntryPoint="readlink", SetLastError = true)] + internal static extern long readlink64(string path, System.IntPtr buf, long bufsize); } } diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index 5dcecfbb..45d84545 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,8 @@ +2015-12-31 Natalia Portillo + + * Commands/DeviceInfo.cs: + Added support for USB detection and metadata. + 2015-12-30 Natalia Portillo * Main.cs: diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index ca163cca..9de26aa5 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -68,6 +68,19 @@ namespace DiscImageChef.Commands return; } + if (dev.IsUSB) + { + DicConsole.WriteLine("USB device"); + if(dev.USBDescriptors != null) + DicConsole.WriteLine("USB descriptor is {0} bytes", dev.USBDescriptors.Length); + DicConsole.WriteLine("USB Vendor ID: {0:X4}", dev.USBVendorID); + DicConsole.WriteLine("USB Product ID: {0:X4}", dev.USBProductID); + DicConsole.WriteLine("USB Manufacturer: {0:X4}", dev.USBManufacturerString); + DicConsole.WriteLine("USB Product: {0:X4}", dev.USBProductString); + DicConsole.WriteLine("USB Serial number: {0:X4}", dev.USBSerialString); + DicConsole.WriteLine(); + } + switch (dev.Type) { case DeviceType.ATA: