2011-08-17 143 views
9

我正在編寫一個C#.Net應用程序,以便在需要拍攝可移動磁盤的映像並將其放到Linux Live USB上的窗口上運行。 Live USB插入目標機器並引導,啓動時運行一個腳本,使用dd命令將其閃爍到另一個驅動器上:Windows C#執行linux dd命令

dd if =/path/to/file/from/csharp/program of =/dev/sdX

我遇到的問題是在Windows端創建映像。我已經用我在Linux系統上使用dd創建的文件嘗試了我的Live Linux,並且工作正常,但我需要能夠在Windows上的C#.Net應用程序內創建這些文件。我寧願不必依靠cygwin或其他依賴項,所以試圖使用Win32 CreateFile函數來打開物理設備。

的CreateFile調用與設置的第一個參數爲「\ \ F:」(如果F:是我想要的圖像驅動器),像這樣:

SafeFileHandle TheDevice = CreateFile(_DevicePath, (uint)FileAccess.Read, (uint)(FileShare.Write | FileShare.Read | FileShare.Delete), IntPtr.Zero, (uint)FileMode.Open, (uint)FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero); 
if (TheDevice.IsInvalid) 
{ 
    throw new IOException("Unable to access drive. Win32 Error Code " + Marshal.GetLastWin32Error()); 
} 
FileStream Dest = System.IO.File.Open(_SaveFile, FileMode.Create); 
FileStream Src = new FileStream(TheDevice, FileAccess.Read); 
Src.CopyTo(Dest); 
Dest.Flush(); 
Src.Close(); 
Dest.Close(); 

但是,當輸出文件爲dd使用Live Linux USB回到磁盤上的結果並不如預期的那樣(磁盤不可啓動等,但是通過在十六進制編輯器中檢查輸出文件,它看起來像在開始時有一個MBR等)。

這是一個endianess問題,還是應該使用FileStream以外的其他方法將數據複製到文件中。

或者是有一個Windows的源代碼的dd的例子(C#或C++,我已經看過Delphi的http://www.chrysocome.net/dd,並沒有完全理解它或有一個體面的Delphi IDE來挑選代碼),所以我可以看到這是如何工作?

UPDATE /編輯:

這裏就是DD輸出包含前512個字節的十六進制字符串:

33 C0 FA 8E D8 8E D0 BC 00 7C 89 E6 06 57 8E C0 FB FC BF 00 06 B9 00 01 F3 A5 EA 1F 06 
00 00 52 52 B4 41 BB AA 55 31 C9 30 F6 F9 CD 13 72 13 81 FB 55 AA 75 0D D1 E9 73 09 66 
C7 06 8D 06 B4 42 EB 15 5A B4 08 CD 13 83 E1 3F 51 0F B6 C6 40 F7 E1 52 50 66 31 C0 66 
99 E8 66 00 E8 21 01 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 
65 6D 2E 0D 0A 66 60 66 31 D2 BB 00 7C 66 52 66 50 06 53 6A 01 6A 10 89 E6 66 F7 36 F4 
7B C0 E4 06 88 E1 88 C5 92 F6 36 F8 7B 88 C6 08 E1 41 B8 01 02 8A 16 FA 7B CD 13 8D 64 
10 66 61 C3 E8 C4 FF BE BE 7D BF BE 07 B9 20 00 F3 A5 C3 66 60 89 E5 BB BE 07 B9 04 00 
31 C0 53 51 F6 07 80 74 03 40 89 DE 83 C3 10 E2 F3 48 74 5B 79 39 59 5B 8A 47 04 3C 0F 
74 06 24 7F 3C 05 75 22 66 8B 47 08 66 8B 56 14 66 01 D0 66 21 D2 75 03 66 89 C2 E8 AC 
FF 72 03 E8 B6 FF 66 8B 46 1C E8 A0 FF 83 C3 10 E2 CC 66 61 C3 E8 62 00 4D 75 6C 74 69 
70 6C 65 20 61 63 74 69 76 65 20 70 61 72 74 69 74 69 6F 6E 73 2E 0D 0A 66 8B 44 08 66 
03 46 1C 66 89 44 08 E8 30 FF 72 13 81 3E FE 7D 55 AA 0F 85 06 FF BC FA 7B 5A 5F 07 FA 
FF E4 E8 1E 00 4F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65 6D 20 6C 6F 61 64 20 65 72 
72 6F 72 2E 0D 0A 5E AC B4 0E 8A 3E 62 04 B3 07 CD 10 3C 0A 75 F1 CD 18 F4 EB FD 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 19 16 9F 29 00 00 80 01 01 00 06 FE 3F 0E 3F 00 00 00 61 C8 03 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA 

,並在這裏是我的代碼產生:

EB 76 90 4D 53 44 4F 53 35 2E 30 00 02 04 04 00 02 00 02 00 00 F8 F2 00 3F 00 FF 00 3F 
00 00 00 61 C8 03 00 80 00 29 7A E8 21 04 4E 4F 20 4E 41 4D 45 20 20 20 20 46 41 54 31 
36 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 E9 05 01 B4 0E 53 33 DB CD 10 5B C3 8A 07 3C 00 74 06 E8 EE FF 43 EB F4 C3 
0D 4E 6F 20 42 50 42 3A 20 43 61 6E 27 74 20 62 6F 6F 74 20 75 73 69 6E 67 20 43 48 53 
20 66 75 6E 63 74 69 6F 6E 73 00 50 B0 2E E8 BC FF 58 33 DB 8E 06 E4 01 F6 06 DC 01 02 
75 42 F6 06 DC 01 04 75 07 80 3E E8 01 80 72 34 53 53 52 50 06 53 55 6A 10 8B F4 52 50 
8A 16 E8 01 B8 00 42 F9 CD 13 8A EC 58 5A 8D 64 10 72 14 80 FD 00 75 0F 03 C5 83 D2 00 
C3 BB 91 00 E8 78 FF F4 EB FD 83 3E 18 00 00 74 F0 52 50 8B CD F7 36 18 00 8B F2 03 D1 
3B 16 18 00 76 06 8B 0E 18 00 2B CE 33 D2 F7 36 1A 00 88 16 E9 01 8B F8 8B D7 51 8A C1 
8D 4C 01 C0 E6 06 0A CE 8A EA 8B 16 E8 01 B4 02 CD 13 59 73 15 80 FC 09 75 0A 49 EB DE 
8A C4 04 30 E8 18 FF B4 00 CD 13 EB D1 58 5A 03 C1 83 D2 00 2B E9 74 07 C1 E1 09 03 D9 
EB 94 C3 00 00 00 00 FA FC E8 00 00 5E 81 EE 85 01 2E 8B 84 E4 01 8E D8 8E C0 8E D0 2E 
C7 84 7C 01 AF 01 2E 89 84 7E 01 B9 00 01 BF 00 00 F3 2E A5 2E FF AC 7C FF BC 00 0A FB 
80 3E E8 01 FF 75 04 88 16 E8 01 83 06 E4 01 20 A1 E0 01 8B 16 E2 01 BD 02 00 E8 E9 FE 
50 52 EB 74 90 00 00 00 00 00 00 00 00 00 00 00 D3 20 00 00 00 30 80 00 FF 00 68 41 00 
40 09 FF 40 5A AC 04 00 00 AC 04 00 00 00 00 12 00 55 AA 

這是從完全相同的CF卡沒有任何編輯/寫作等發生,所以我很困惑,爲什麼他們如此不同,但都e找到正確的55個AA字節。當Windows以這種方式訪問​​Windows時是否會破壞MBR的內容,或者在我不知道的情況下發生了什麼?

+0

我假設從你的C#代碼使用從cygwin調用「dd」是不可能的? – Greg 2011-08-17 12:23:31

+0

這將是最後的手段,我認爲問題是將//./F:路徑轉換爲cygwin可以理解的dd。所以這個問題(對我來說)變成了如何在C#應用程序中將我的//./F:路徑轉換爲cygwin中的/ dev/sdX。 – 2011-08-17 12:38:38

回答

4

我想你應該有什麼工作 - 我已經使用可啓動的軟盤映像(使用ImDisk作爲虛擬驅動器掛載)自己嘗試過,並且生成的文件與原始映像二進制文件相同。

爲了完整這裏是我使用的代碼(在其條款內容):

using System; 
using System.IO; 
using System.Runtime.InteropServices; 
using Microsoft.Win32.SafeHandles; 

namespace ConsoleApplication1 
{ 
    public class Program 
    { 
     const int FILE_ATTRIBUTE_SYSTEM = 0x4; 
     const int FILE_FLAG_SEQUENTIAL_SCAN = 0x8; 

     [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     public static extern SafeFileHandle CreateFile(string fileName, [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, int flags, IntPtr template); 

     [STAThread] 
     static void Main() 
     { 
      using (SafeFileHandle device = CreateFile(@"\\.\E:", FileAccess.Read, FileShare.Write | FileShare.Read | FileShare.Delete, IntPtr.Zero, FileMode.Open, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero)) 
      { 
       if (device.IsInvalid) 
       { 
        throw new IOException("Unable to access drive. Win32 Error Code " + Marshal.GetLastWin32Error()); 
       } 
       using (FileStream dest = File.Open("TempFile.bin", FileMode.Create)) 
       { 
        using (FileStream src = new FileStream(device, FileAccess.Read)) 
        { 
         src.CopyTo(dest); 
        } 
       } 
      } 
     } 
    } 
} 

如果不工作,那麼它似乎表明:

  1. 沒有與問題原始圖像。
  2. 問題在於無論使用的是您剛寫入的磁盤映像。
  3. 有與您正在訪問的特定裝置處理(雖然我想不出什麼)

最有可能的罪魁禍首是第2步到底是什麼,你到底用做一些細微的差別產生的磁盤映像?


更新:這是寫在評論,但出於完整性我想我把它添加到我的答案 - 它看起來像發生了什麼是磁盤的第一個分區的內容正在寫,而不是想要的是整個磁盤的內容。

當你看一看的東西第二十六進制字符串(由示例代碼中製作的)像HxD我們看到:

ëv.MSDOS5.0..........øò.?.ÿ.?...aÈ..€.)zè!.NO NAME FAT16 .. 
........................................................é..´.S3Û 
Í.[Ê.<.t.èîÿCëôÃ.No BPB: Can't boot using CHS functions.P°.è¼ÿX 
3ÛŽ.ä.ö.Ü..uBö.Ü..u.€>è.€r4SSRP.SUj.‹ôRPŠ.è.¸.BùÍ.ŠìXZ.d.r.€ý.u. 
.ŃÒ.û‘.èxÿôëýƒ>...tðRP‹Í÷6..‹ò.Ñ;...v.‹...+Î3Ò÷6..ˆ.é.‹ø‹×QŠÁ. 
L.Àæ..Ίê‹.è.´.Í.Ys.€ü.u.IëÞŠÄ.0è.ÿ´.Í.ëÑXZ.ÁƒÒ.+ét.Áá..Ùë」Ã.... 
úüè..^.î…..‹„ä.ŽØŽÀŽÐ.Ç„|.¯..‰„~.¹..¿..ó.¥.ÿ¬|ÿ¼..û€>è.ÿu.ˆ.è.ƒ. 
ä. ¡à.‹.â.½..èéþPRët............Ó ...0€.ÿ[email protected]ÿ@Z¬...¬.......Uª 

這在我看來就像boot sector of a FAT16 partition - 琴絃的存在開始附近的「MSDOS5.0」,「NO NAME」和「FAT16」是一個死牌。

比較這對第一個十六進制字符串(由DD產生的一個)的輸出:

3ÀúŽØŽÐ¼.|‰æ.WŽÀûü¿..¹..ó¥ê....RR´A»ªU1É0öùÍ.r..ûUªu.Ñés.fÇ...´B 
ë.Z´.Í.ƒá?Q.¶Æ@÷áRPf1Àf™èf.è!.Missing operating system...f`f1Ò». 
|fRfP.Sj.j.‰æf÷6ô{Àä.ˆáˆÅ’ö6ø{ˆÆ.áA¸..Š.ú{Í..d.faÃèÄÿ¾¾}¿¾.¹ .ó¥ 
Ãf`‰å»¾.¹..1ÀSQö.€[email protected]‰ÞƒÃ.âóHt[y9Y[ŠG.<.t.$.<.u"f‹G.f‹V.f.Ðf!Òu. 
f‰Âè¬ÿr.è¶ÿf‹F.è ÿƒÃ.âÌfaÃèb.Multiple active partitions...f‹D.f. 
F.f‰D.è0ÿr..>þ}Uª.….ÿ¼ú{Z_.úÿäè..Operating system load error...^ 
¬´.Š>b.³.Í.<.uñÍ.ôëý......................................Ÿ)..€. 
...þ?.?...aÈ..................................................Uª 

而且我們看到的東西,在我看來很像master boot record。爲什麼?因爲在MBR中,所有前440個字節都是引導代碼,與包含獨特BIOS參數塊的FAT引導扇區不同(它看起來像上面的垃圾,但如果你通過反彙編程序來做這件事,你會看到有效的16位碼)。

此外,這兩個看起來像有效和完全不同的引導扇區(完整的錯誤消息)。編程錯誤不可能使一個看起來像另一個看起來「變形」 - 它只能是錯誤的東西被讀取。


爲了獲得CreateFile返回磁盤,而不是它看起來像你只需要通過一個不同的字符串格式的分區,例如@"\\.\PhysicalDrive0"打開第一個物理磁盤。

參見:

1

這就是我寫做得到\ \對於給定的驅動器盤符PhysicalDriveX路徑。如果將驅動器號傳遞給此函數並將返回值傳遞給CreateFile作爲第一個參數,我現在應該在Linux下獲得與dd相似的內容。

using System.Management; //Add in a reference to this as well in the project settings 
public static string GetPhysicalDevicePath(char DriveLetter) 
{ 
    ManagementClass devs = new ManagementClass(@"Win32_Diskdrive"); 
    { 
     ManagementObjectCollection moc = devs.GetInstances(); 
     foreach(ManagementObject mo in moc) 
     { 
      foreach (ManagementObject b in mo.GetRelated("Win32_DiskPartition")) 
      { 
       foreach (ManagementBaseObject c in b.GetRelated("Win32_LogicalDisk")) 
       { 
        string DevName = string.Format("{0}", c["Name"]); 
        if (DevName[0] == DriveLetter) 
         return string.Format("{0}", mo["DeviceId"]); 
       } 
      } 
     } 
    } 
    return ""; 
}