2011-08-17 19 views
9

Sto scrivendo un'app C# .Net per eseguire su Windows che deve prendere un'immagine di un disco rimovibile e inserirla su un Linux Live USB. Live USB è inserito nel computer di destinazione e si avvia, all'avvio esegue uno script che utilizza il comando dd come tale per visualizzarlo su un'altra unità:Implementazione di Windows C# del comando dd linux

dd if =/percorso/to/file/da/csharp/programma di =/dev/sdX

Il problema che sto avendo è la creazione dell'immagine sul lato Windows. Ho provato il mio Live Linux con i file che ho creato su un sistema Linux usando dd e che funziona bene, ma ho bisogno di essere in grado di creare questi file da un'applicazione C# .Net su Windows. Preferirei non dover fare affidamento su cygwin o altre dipendenze, quindi ho provato ad utilizzare la funzione CreateFile di Win32 per aprire il dispositivo fisico.

CreateFile viene chiamato con il primo arg impostato su "\ \ F:." (Se F: è l'unità che voglio immagine), in questo modo:

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

Ma quando il file di output è dd 'su un disco che usa Live Linux USB il risultato non è come previsto (il disco non è avviabile ecc., ma esaminando il file di output in un editor esadecimale, sembra che ci sia un MBR all'inizio, ecc.).

Si tratta di un problema con endianess o dovrei utilizzare qualcosa di diverso da un FileStream per copiare i dati nel file.

In alternativa c'è un esempio di dd per il codice sorgente di Windows (C# o C++, ho guardato il Delphi per http://www.chrysocome.net/dd e non lo capisco completamente o ho un IDE Delphi decente per distinguere il codice) quindi puoi vedere come funziona?

UPDATE/EDIT:

Ecco una stringa esadecimale dei primi 512 byte che l'uscita dd contiene:

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 

e qui è quello che il mio codice produce:

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 

Questo è stato preso dalla stessa scheda CF senza che sia mai accaduto alcun editing/scrittura, quindi sono confuso sul motivo per cui sono così diversi, ma entrambi con anche i 55 byte AA corretti. Windows maneggia l'MBR sulle carte quando vi si accede in questo modo o sono altre strane cose che accadono di cui non sono a conoscenza?

+0

Sto assumendo che l'utilizzo di "dd" da cygwin dal codice C# sia fuori questione? – Greg

+0

Sarebbe un'ultima risorsa, il problema che penso abbia è la conversione del //./F: percorso in qualcosa che dd sotto cygwin capisce. Quindi il problema (per me) diventa come all'interno dell'applicazione C# convertire il mio //./F: percorso in/dev/sdX in cygwin. –

+1

@Kragen Penso che quello che sta succedendo qui sia che la versione di Windows sta ottenendo il Volume Boot Record non il Master Boot Record. Questo è probabilmente perché sto passando ad esso //./F: e F: è solo la prima partizione, non il Disco Fisico.Sarebbe bello se qualcun altro potesse confermare se sono corretto o meno prima di entrare nella prossima domanda su come accedere al Disco Fisico (invece di partizione/volume). –

risposta

4

Penso che dovrebbe funzionare: l'ho provato io stesso utilizzando un'immagine di disco floppy avviabile (montata come unità virtuale usando ImDisk) e il file risultante è binario identico all'immagine originale.

Per completezza ecco il codice che ho usato (nella sua interezza):

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

Se questo non funziona allora sembra indicare che:

  1. C'è un problema con la immagine originale.
  2. Il problema è con qualsiasi cosa stia usando l'immagine del disco che hai appena scritto.
  3. C'è alcune sottili differenze nel trattare con il dispositivo specifico si accede (anche se non posso pensare che cosa)

Il colpevole più probabile è il punto 2. Che cosa è esattamente che si sta facendo con il immagine del disco risultante?


Aggiornamento: Questo è scritto nei commenti, ma per completezza ho pensato di aggiungerlo alla mia risposta - sembra che tutto quello che succede è che il contenuto della prima partizione del disco è in scritto, quando invece ciò che si desidera è il contenuto dell'intero disco.

Quando si dà un'occhiata alla seconda stringa esadecimale (quello prodotto da codice di esempio) in qualcosa di simile HxD vediamo questo:

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

Questo mi sembra il boot sector of a FAT16 partition - la presenza delle corde "MSDOS5.0", "NO NAME" e "FAT16" vicino all'avvio sono un regalo non valido.

confronta questo con l'uscita della prima stringa esadecimale (quello prodotto da 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ª 

e vediamo qualcosa che sembra a me un po 'come un master boot record. Perché? Perché nel MBR tutti i primi 440 byte sono il codice di avvio, a differenza di un settore di avvio FAT che contiene il blocco di parametri bios distintivo (sembra spazzatura sopra, ma se lo metti attraverso un disassemblatore ottieni qualcosa che assomiglia a 16 bit validi codice).

Inoltre, entrambi sembrano settori di avvio validi e completamente diversi (completi di messaggi di errore). Non c'è modo che un errore di programmazione possa avere "mutilato" uno per assomigliare all'altro - deve essere solo che la cosa sbagliata viene letta.


Al fine di ottenere CreateFile di restituire il disco invece della partizione sembra che hai solo bisogno di passare una stringa diverso, ad esempio @"\\.\PhysicalDrive0" apre il primo disco fisico.

See:

+0

Alcune informazioni di base, che spiegherò cosa sto facendo in modo più dettagliato. I nostri vecchi sistemi erano utilizzati per l'avvio da una scheda CF formattata FAT, quindi per aggiornare il software sul sistema, si dovrebbe semplicemente rispolverare la scheda CF utilizzando un'app di Windows. Il nuovo sistema non ha alcun supporto per l'avvio da schede CF, ma ha un disco rigido e una porta USB. Quindi il piano era, come prima di usare l'app di Windows per far lampeggiare la scheda CF, quindi scattare una foto di quella scheda CF (in Windows con la mia app C#) copiarla sul Live USB che poi lampeggierebbe il disco rigido, dal Ambiente Linux live usando dd, con l'immagine della scheda CF –

+0

Non penso che sia il passo 2 come se inserissi un'immagine che ho creato dal CF usando una VM Linux e dd su Live USB che funziona. –

+0

@rb_ 7 Ah vedo - quindi l'immagine viene infine scritta su un disco rigido. In questo caso non sono sicuro del motivo per cui non funziona - finché il primo settore (512 byte) termina con i byte di firma "bootsector valido" (0x55, 0xAA) il BIOS dovrebbe andare avanti e avviare utilizzando quel settore di avvio. La mia ** supposizione ** sarebbe che il BIOS stia effettivamente usando quel settore di avvio, ma le differenze hardware significano che il boot loader (che precedentemente funzionava sul vecchio sistema) non funziona sul nuovo sistema. – Justin

1

Questo è quello che ho scritto per fare ottenere il \ \ percorso PhysicalDriveX per una determinata lettera di unità.. Se passate la lettera di unità in questo e prendete il valore restituito e passate in CreateFile come primo parametro dovrei ora ottenere qualcosa di simile a dd sotto Linux.

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