2011-08-17 22 views
9

Piszę aplikację C# .Net do uruchomienia w oknach, które muszą zrobić zdjęcie dysku wymiennego i przenieść go do Linux Live USB. Live USB jest włożona do urządzenia docelowego i buty, na rozruchu uruchamia skrypt, który używa komendy dd jak tak migać go na innym dysku:Windows C# implementacja polecenia linux dd

dd if =/ścieżka/plik// z/csharp/program =/dev/sdX

Problemem jest tworzenie obrazu po stronie systemu Windows. Wypróbowałem mój Live Linux z plikami, które utworzyłem na systemie Linux przy użyciu dd i działa dobrze, ale muszę mieć możliwość tworzenia tych plików z poziomu aplikacji C# .Net w systemie Windows. Wolałbym nie polegać na cygwin lub jakiejś innej zależności, więc spróbowałem użyć funkcji Win32 CreateFile, aby otworzyć fizyczne urządzenie.

CreateFile nazywany jest z pierwszym arg ustawiony na "\ \ F:." (Jeżeli F: to dysk Chcę obrazu), tak jak poniżej:

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(); 

Ale gdy plik wyjściowy jest dd Z powrotem na dysk za pomocą Live Linux USB wynik nie jest taki, jak oczekiwano (dysk nie jest bootowalny itp., ale od sprawdzenia pliku wyjściowego w edytorze szesnastkowym, wygląda na to, że istnieje MBR na początku itd.).

Czy to jest problem z endianessą, czy też powinienem użyć czegoś innego niż FileStream do skopiowania danych do pliku.

Alternatywnie istnieje przykład dd dla kodu źródłowego Windows (C# lub C++, patrzyłem na Delphi dla http://www.chrysocome.net/dd i nie rozumiem go całkowicie lub nie mam przyzwoitego IDE Delphi, aby wybrać kod), więc widzisz, jak to działa?

UPDATE/EDIT:

Oto ciąg hex z pierwszych 512 bajtów, że wyjście dd zawiera:

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 

i tutaj jest to, co mój kod produkuje:

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 

Zostało to zrobione z dokładnie tej samej karty CF bez edytowania/pisania itp., Więc jestem zdezorientowany, dlaczego są tak różne, ale oba także z poprawnymi 55 bajtami AA. Czy system Windows maskuje MBR na kartach, gdy są one dostępne w ten sposób, czy też inne dziwne rzeczy, których nie znam?

+0

Zakładam, że używanie funkcji "dd" z cygwin z kodu C# jest wykluczone? – Greg

+0

To byłaby ostatnia deska ratunku, problem, który moim zdaniem przekształca //./F: path w coś, co dd pod cygwinem rozumie. Więc problem (dla mnie) staje się wtedy, jak w aplikacji C# przekonwertować moją //./F: ścieżkę do/dev/sdX w cygwin. –

+1

@Kragen Myślę, że to, co się tutaj dzieje, to że wersja systemu Windows uzyskuje rekord rozruchowy woluminu, a nie Master Boot Record. Jest tak prawdopodobnie dlatego, że przechodzę do niego //./F: i F: jest po prostu pierwszą partycją, a nie dyskiem fizycznym.Byłoby miło, gdyby ktoś inny mógł potwierdzić, czy mam rację, czy nie, zanim przejdę do następnego pytania o to, jak uzyskać dostęp do dysku fizycznego (zamiast partycji/woluminu). –

Odpowiedz

4

Myślę, że to, co powinieneś, powinno działać - próbowałem tego sam, używając bootowalnego obrazu dyskietki (zamontowanego jako wirtualny napęd przy użyciu ImDisk), a wynikowy plik jest binarny identyczny z obrazem oryginalnym.

Dla kompletności Oto kod Kiedyś (w jego entirity):

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); 
        } 
       } 
      } 
     } 
    } 
} 

Jeśli to nie poskutkuje, to wydaje się wskazywać, że:

  1. Istnieje problem z oryginalny obraz.
  2. Problem dotyczy tego, co jest używane do zapisania obrazu dysku, który właśnie napisałeś.
  3. Istnieje pewne subtelne różnice w kontaktach z konkretnego urządzenia, z którego uzyskuje dostęp (choć nie mogę myśleć co)

najbardziej prawdopodobnym winowajcą jest krok 2. Co to jest dokładnie to, że robisz z wynikowy obraz dysku?


Aktualizacja: To jest napisane w komentarzach, ale dla kompletności Myślałam, że go dodać do mojej odpowiedzi - wygląda na to, co dzieje się, że zawartość pierwszej partycji dysku jest bycie napisane, gdy zamiast tego, co jest pożądane, jest zawartość całego dysku.

Gdy spojrzeć na drugim ciągiem szesnastkowym (jednego wyprodukowany przez przykładowy kod) w czymś takim HxD widzimy to:

ë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ª 

To mi wygląda na boot sector of a FAT16 partition - obecność struny "MSDOS5.0", "NO NAME" i "FAT16" blisko początku to martwy gratisów.

Porównaj to do wyjścia pierwszego ciągu hex (jednego wyprodukowany przez 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ª 

I widzimy coś, co wygląda mi dużo jak master boot record. Czemu? Ponieważ w MBR wszystkie pierwsze 440 bajtów jest kodem rozruchowym, w przeciwieństwie do sektora rozruchowego FAT, który zawiera charakterystyczny blok parametrów biosu (wygląda jak śmieci powyżej, ale jeśli umieścisz to przez deasembler, otrzymasz coś, co wygląda jak poprawny 16 bitowy kod).

Ponadto oba te elementy wyglądają jak poprawne i całkowicie różne sektory rozruchowe (wraz z komunikatami o błędach). Nie ma możliwości, aby błąd programistyczny "zniekształcił" jeden, by wyglądał jak drugi - musi po prostu być tak, że odczytuje się coś niewłaściwego.


W celu uzyskania CreateFile wrócić dysk zamiast partycji to wygląda po prostu trzeba przekazać mu inny ciąg znaków, na przykład @"\\.\PhysicalDrive0" otwiera pierwszy dysk fizyczny.

Patrz:

+0

Kilka dodatkowych informacji, które wyjaśnią szczegółowo, co robię. Nasze stare systemy były używane do rozruchu z karty CF sformatowanej w systemie FAT, więc aby zaktualizować oprogramowanie w systemie, wystarczy przeprogramować kartę CF za pomocą aplikacji Windows. Nowy system nie obsługuje rozruchu z kart CF, ale ma dysk twardy i port USB. Plan był taki, jak przed użyciem aplikacji windowsowej do flashowania karty CF, a następnie zrobienia zdjęcia tej karty CF (w oknach z moją aplikacją C#) skopiuj ją na Live USB, która następnie zapali dysk twardy, z Żywe środowisko Linuxa używające dd, z obrazem karty CF –

+0

Nie sądzę, że jest to krok 2, tak jakbym wstawił obraz, który stworzyłem z CF przy użyciu maszyny wirtualnej Linux i dd na Live USB, to działa. –

+0

@rb_ 7 Ah Widzę - więc obraz zostanie ostatecznie zapisany na dysku twardym. W takim przypadku nie jestem pewien, dlaczego nie działa - dopóki pierwszy sektor (512 bajtów) kończy się bajtami podpisu "prawidłowego bootsektora" (0x55, 0xAA), BIOS powinien po prostu zacząć i uruchamiać się przy użyciu tego sektora rozruchowego. Domyślam się, że system BIOS faktycznie używa tego sektora rozruchowego, ale różnice sprzętowe oznaczają, że program ładujący (który wcześniej działał w twoim starym systemie) zawodzi w nowym systemie. – Justin

1

To co napisałem to zrobić uzyskać \ \ ścieżka PhysicalDriveX dla danej litery dysku.. Jeśli przekaż literę napędu i przyjmij wartość zwracaną i przejdź do CreateFile jako pierwszego Param, powinienem dostać coś podobnego do dd pod Linuksem.

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 ""; 
}