2014-09-08 25 views
5

Ho scritto un programma di utilità per le informazioni della directory e (poiché io e le persone che ho scritto per raccogliere & utilizzano hardware vintage), reso compatibile con DOS e Windows 9x e Windows XP/Vista/7/8 64-bit (perché li usiamo anche noi.) Il problema che ho avuto è stato con le unità Windows 9x e FAT32. Sono riuscito a farlo funzionare fino a quando Windows 9x è stato effettivamente caricato, ma se avvio solo il prompt dei comandi, o riavvio in modalità MS-DOS, perdo l'accesso all'API di Windows che mi ha permesso di ottenere i dati di unità di grandi dimensioni e è tornato di default alla routine DOS che ho. Questi sono limitati alle routine limite da 2 GB. Esaminando come i programmi DOS 7.x (principalmente chkdsk) gestiscono questo (poiché non hanno problemi nel riportare le dimensioni corrette dell'unità), sembra che utilizzino gli interrupt DOS (principalmente INT 21h) per farlo. Pensando, nessun problema, farò un rapido controllo della versione, e se è DOS 7 o superiore eseguirò semplicemente un rapido instradamento dell'assemblaggio per ottenere la struttura dell'azionamento e calcolare il totale dello spazio libero & in questo modo. Solo, la routine (anche se non restituisce un errore) non riempie il mio buffer di nulla.Ottenere grandi informazioni sulla struttura dell'unità in DOS 7.x

Ecco il codice:

#include <stdio.h> 
#include <dos.h> 

void main(void) { 
    unsigned short hes,hdi,sectors,bytes; 
    unsigned long tclusters,fclusters; 
    unsigned char far *drivedata; 
    char test = '\0'; 
    char display[17] = "ABCDEF"; 
    int count; 

    drivedata = new unsigned char [63]; 

    for (count = 0; count < 63; count++) drivedata[count] = '\0'; 

    drivedata[0] = '\x3d'; 
    drivedata[1] = '\x00'; 

    hes = FP_SEG(drivedata); 
    hdi = FP_OFF(drivedata); 

asm { 
     push ax 
     push es 
     push di 
     push ds 
     push dx 
     push cx 
     mov ax,0x440d 
     mov bx,0x0003 
     mov cx,0x484a 
     int 21h 
     jnc _GOOD 
     mov ax,0x7302 
     mov es,[hes] 
     mov di,[hdi] 
     mov dx,0x0003 
     mov cx,0x003f 
     int 21h 
     jnc _GOOD 
    } 
    test = '\1'; 
_GOOD: 
    asm { 
     mov ax,0x440d 
     mov bl,0x03 
     mov cx,0x486a 
     int 21h 
     pop cx 
     pop dx 
     pop ds 
     pop di 
     pop es 
     pop ax 
    } 

    if (test == '\1') { 
     printf("There was an error.\r\n"); 
     return; 
    } 



    tclusters = (unsigned long) drivedata[48]; 
    tclusters = (tclusters * 256) + (unsigned long)drivedata[47]; 
    tclusters = (tclusters * 256) + (unsigned long)drivedata[46]; 
    tclusters = (tclusters * 256) + (unsigned long)drivedata[45]; 
    ++tclusters; 

    fclusters = (unsigned long)drivedata[36]; 
    fclusters = (fclusters * 256) + (unsigned long)drivedata[35]; 
    fclusters = (fclusters * 256) + (unsigned long)drivedata[34]; 
    fclusters = (fclusters * 257) + (unsigned long)drivedata[33]; 

    bytes = (unsigned int)drivedata[5]; 
    bytes = (bytes * 256) + (unsigned int)drivedata[4]; 

    sectors = (unsigned long)drivedata[6]; 
    ++sectors; 

    printf("Drive C has:\r\n"); 
    printf(" Total Clusters: %u\r\n",tclusters); 
    printf(" Free Clusters: %u\r\n",fclusters); 
    printf("   Sectors: %u\r\n",sectors); 
    printf("   Bytes: %u\r\n",bytes); 

    printf("\r\n"); 
    printf(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n"); 
    printf("---------------------------------------------------------------------"); 
    for (count = 0; count < 63; count++) { 
     if ((count % 16) == 0) printf("\r\n %c | ",display[(count/16)]); 
     printf("%03u ",drivedata[count]); 
    } 
    printf("\r\n"); 

    return; 
} 

che l'ultimo pezzo mi stava cercando di capire che cosa stava andando male. Stavo ottenendo risultati strani, e non riuscivo a capire un modello. Originariamente, non ero preoccupato di cancellare il buffer poiché la chiamata INT avrebbe dovuto riempirlo con i propri valori (tranne i primi 2 byte, che dovrebbero essere riempiti con la dimensione del buffer dei dati EDB.) Dopo aver ricevuto così tanti apparentemente risultati casuali, ho aggiunto il ciclo all'inizio per riempire il buffer con gli zeri, quindi aggiungere la dimensione del buffer. I risultati hanno smesso di essere casuali in quel momento, erano invariabilmente tutti zero, il che significa che la chiamata INT non riempie il buffer. Con una serie di test, ho confermato che ai hes & hdi viene assegnato correttamente il segmento e l'offset dell'indirizzo del buffer. Ho anche provato es & di all'indirizzo dell'indicatore invece dell'indirizzo del buffer. Non pensavo che avrebbe funzionato come tutto quello che ho letto ha detto di impostare l'indirizzo e non un puntatore, ma stavo cercando tutto quello che potevo pensare. In tutti i casi, il buffer non si riempie di nulla.

Come si può probabilmente dire, questo è solo un programma di prova che sto scrivendo per capire la procedura esatta prima di aggiungerlo al mio programma principale (che funziona bene tranne per questo problema.) Le linee FP_ sono solo macro che possono essere indicati come (senza firma lunga) (x & 0xffff0000) >> 16 per il segmento e (senza segno lungo) (x & 0x0000ffff) per lo scostamento. Normalmente si passa il puntatore (& drivedata), ma drivedata è già un puntatore.

L'uscita effettiva:

Drive C has: 
    Total Clusters: 1 
    Free Clusters: 0 
      Sectors: 1 
      Bytes: 0 

    | 0 1 2 3 4 5 6 7 8 9 A B C D E F 
--------------------------------------------------------------------- 
0 | 061 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 
1 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 
2 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 
3 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 

Allora, che cosa mi manca? Come chkdsk, sto bloccando l'unità prima e sbloccandola dopo la chiamata (anche se non sono sicuro della necessità). Come posso farlo funzionare correttamente? In alternativa, esiste un modo migliore per ottenere la struttura dell'unità (cluster, settori per cluster, byte per settore) rispetto all'utilizzo di INT 21h? Tutto ciò che trovo nelle ricerche mi indica solo le funzioni API di Windows, a cui l'utente non può accedere, se eseguono un avvio al prompt dei comandi ecc ...

+1

Sto leggendo il tuo codice sbagliato? Sembra che se riesci a bloccare l'unità, salti il ​​codice per leggere i dati. In caso contrario, forse 1) Impostazione SI a 0xF1A6. 2) Impostazione di dl su 0x80. 3) Utilizzo di un buffer più grande (256?). –

+1

In realtà, non lo sei:/Mi sono perso ... Ricompilazione ora ... Indietro in un sec. – user3399848

+1

*** sigh *** Sì, stavo saltando il mio codice sul successo, invece di saltare sul fallimento. Modificato l'opcode jnc su jc e aggiunto in una nuova etichetta (per cambiare in modo appropriato la flag good/bad). Il mio male. Bene, ora sto ricevendo dati, anche se i numeri sembrano spenti. Sto per fare qualche altro test ora :) Grazie – user3399848

risposta

1

Wow, usando DOS, è vecchia scuola! Non come vecchia scuola come l'uso di schede perforate, ma ancora ...

Apparentemente, FreeDOS ha FAT 32 support. Si potrebbe provare a installarlo su quelle macchine che non hanno nemmeno Windows 95 installato.

+3

Le persone che costruiscono sistemi vintage tendono ad attaccarsi con il sistema operativo che era in uso al momento.Il mio piccolo programma funziona su DOS 3 + (in realtà, fin da quando volevo installare e testare, potrebbe tornare indietro.) Funziona anche su sistemi moderni (ad esempio il mio Windows 7 a 64 bit.) L'unico problema, è DOS 7 (Windows 9x avviato al prompt dei comandi.) Ecco cosa sto cercando di far funzionare ora, DOS 7. Solo una FYI, sono stato davvero contento quando hanno inventato la tastiera, le schede perforate erano una vera PITA – user3399848

+0

Wow, dovresti * sicuramente * controllare questo su CP/M! – zmbq

1

Per il tuo hobby vintage dovresti dotarti delle specifiche LBA e FAT32, Wikipedia: File Allocation Table sembra avere buoni collegamenti.

Una cosa che si può scoprire è che quei sistemi legacy (e del software scritti per loro) non potevano gestire grandi dischi (dimensione del disco> 2^(32-1)) con grazia.

Altro materiale Credo che sarebbe molto importante:

Il "modo migliore", che dovrebbe funzionare per voi in ogni caso sarebbe quella di utilizzare chiamate del BIOS per scoprire tutte le basi e quindi replicare gli algoritmi per calcolare le dimensioni ecc. nel proprio codice. Nei vecchi giorni DOS non esisteva API facilmente riutilizzabile disponibile per programmi non Microsoft. I programmi che dovevano fare cose avanzate dovevano sapere come farlo da soli.

+1

sto usando le chiamate del BIOS ora, questo è dove ho incontrato il problema :(Ho letto su LBA e FAT32. Ho fatto tutto ciò quando stavo scrivendo la piccola utilità. Come puoi vedere sopra, risulta che i miei problemi erano tutti della mia stessa creazione. Mi dispiace, non sono un programmatore professionista, solo un dilettante. L'ho risolto quasi sempre ora. Un bug minore da rintracciare (nel codice di utilità effettivo) e una soluzione alternativa per i CD-ROM e io dovrei essere finito. – user3399848