Capítulo – 10
RECUPERANDO DADOS DE UM DISCO DANIFICADO
Recuperando dados de um disquete danificado
Um disquete é uma das fontes menos confiáveis de armazenamento de dados. Se você for a qualquer organização que usa sistemas de computador e perguntar aos seus funcionários sobre problemas causados por disquetes, você ouvirá frequentemente que o problema é que um funcionário da organização tinha alguns dados importantes em seu disquete e agora o disquete não pode ser lido pelo computador e uma mensagem aparece na tela semelhante a:
"Não foi possível ler o disco"
"Faixa 0 incorreta"
"Disco ou capacidade inválida"
"Disco não formatado. Você quer formatá-lo agora?
Este é um problema diário para organizações que usam sistemas de computador e disquetes. O problema se torna crítico quando você descobre que nenhum backup foi feito ou não há backup disponível para os dados que parecem estar perdidos no disquete danificado.
O maior problema ocorre quando você está fazendo backup de informações críticas em um disquete, restaurando discos de programas antivírus para superar um ataque de vírus, ou registros de inicialização ou outros backups (pode haver várias opções) em um disquete, e quando você deseja reutilizar o backup do disquete, ocorre um erro de leitura.
Nesse caso, você corre o risco de perder informações e dados importantes e, em alguns casos, quando você sente a falta de backups e programas de recuperação das informações de inicialização do seu computador, programas de resgate de ataques de vírus , etc., você pode sofrer uma grande perda de dados na forma de falha do sistema operacional devido à falta de informações armazenadas no disquete, que não podem ser lidas pelo computador no momento.
Nesses casos, o requisito mais importante é recuperar dados de um disquete que o sistema do seu computador reconheceu como defeituoso.
Por que o disquete não está legível?
O problema mais comum que faz com que um disquete apresente mensagens de erro como essas é a corrupção do DOS Boot Record (DBR) do disquete, que ajuda o computador a saber a identidade lógica do disquete.
O DBR é um pequeno programa armazenado na trilha 0, cabeça 0 e setor 1 que contém informações importantes sobre o disquete, como:
- Número de bytes por setor
- Setor por cluster
- Número de FAT
- Número máximo de diretórios raiz, etc.
Como o disquete não tem um sistema de partição lógica, não há MBR no disquete. O primeiro setor do disquete contém o DBR. Essa também é a principal diferença ao comparar a estrutura lógica de um disco rígido com um disquete.
Quando lemos as informações do setor de boot do disquete usando qualquer programa de edição de disco, ele exibirá informações como a mostrada na imagem abaixo.
A figura a seguir mostra 512 bytes de informações DBR em um disquete de 1,44 MB e 3½ polegadas.

Se essas informações forem danificadas de alguma forma ou se tornarem ilegíveis, o disquete produzirá essas mensagens de erro de leitura. Isso pode ser devido a danos físicos ou lógicos no primeiro setor do disco.
Corrupção lógica inclui casos em que as informações no primeiro setor do disquete são alteradas, há algum setor logicamente danificado ou o DBR do disquete é danificado por algum outro motivo.
Presume-se que ocorra dano físico se o primeiro setor do disquete tiver setores físicos defeituosos (ou seja, o setor 1 estiver fisicamente danificado). O problema se torna mais sério quando você descobre que o disquete tem mais de um setor defeituoso na trilha 0.
Como recuperar
Agora que aprendemos as duas causas dos danos, espero que agora você consiga entender o problema. Não é tão difícil recuperar dados de corrupção lógica, mas recuperar dados de corrupção física requer um pouco mais de esforço.
Método – 1
Salve uma imagem inicializável de qualquer novo disquete.
Se o problema for lógico, agora entendemos como podemos recuperar os dados . O que precisamos fazer é apenas obter o registro de inicialização apropriado de outro disquete do mesmo tamanho e capacidade e colá-lo no primeiro setor do disquete ilegível. Embora o problema tenha sido criado devido ao registro de inicialização ruim , ele deve funcionar agora.
Há duas etapas envolvidas neste procedimento, seguindo as quais recuperaremos nossos dados de um disquete ilegível:
- Fazendo a imagem do DOS Boot Record de um disquete bom
- Colando a imagem de boot no primeiro setor de um disquete ilegível
Fazendo a imagem do DOS Boot Record de um disquete bom
Para armazenar a imagem do registro de inicialização de um disquete novo, o programa deve executar as três tarefas a seguir:
- Leia exatamente os primeiros 512 bytes do disquete bom
- Verifique se a operação de leitura foi bem-sucedida (mais importante)
- Armazene esses 512 bytes no nome do arquivo e no caminho de destino especificados
O setor do disquete tem 512 bytes e é necessário copiar a imagem exata do setor. É o passo mais importante e necessário no caso de qualquer tipo de operação aplicada no disquete para verificar se a operação foi bem-sucedida ou não.
Pode haver algum problema de inicialização mesmo com o disquete bom e novo. É por isso que na maioria dos casos quando a operação é realizada em disquetes, primeiro a inicialização dos disquetes é realizada na programação com a operação de reset do disco (Função 00 H de INT 13H).
Se, mesmo após a inicialização, o disquete inserido recentemente ou o disquete alterado causar algum erro de leitura , é recomendável executar o programa novamente, pois provavelmente ele funcionará desta vez.
O programa a seguir é para executar essas tarefas especificadas. Vamos ver como ele procede:
/* Armazene a imagem de inicialização em um arquivo de um disquete novo */
#incluir <bios.h>
#incluir <stdio.h>
int principal(vazio)
{
estrutura diskinfo_t dinfo;
sindicato REGS regs;
int resultado;
int contagem=0, i;
char fname[80];
char estático dbuf[512];
ARQUIVO *fp;
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = 0; /* número da cabeça do disco */
dinfo.track = 0; /* número da trilha */
dinfo.sector = 1; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
clrscr();
gotoxy(10,3);cprintf("Digite o nome do arquivo e o caminho para
Armazene a imagem de inicialização");
gotoxi(5,5);
obtém(fname);
fp=fopen(nomef,"wb");
se((fp=fopen(fname,"wb"))==NULL)
{
vídeo alto();
gotoxy(10,10);cprintf("O arquivo não pôde ser criado");
obter();
saída(0);
}
gotoxi(10,9);
cprintf("Tentando ler da unidade de disquete :\n");
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
resultado = _bios_disk(_DISK_READ, &dinfo);
se ((resultado & 0xff00) == 0)
{
enquanto(contagem<512)
{
fprintf(fp,"%c",dbuf[contagem] & 0xff );
contar++;
}
fclose(fp);
gotoxy(10,14);cprintf("Disco lido da unidade de disquete
: bem-sucedido.\n");
}
outro
{
gotoxi(10,14);
cprintf("Não é possível ler a unidade A, status = 0x%02x\n", resultado);
switch(resultado)
{
caso 0x00:
cprintf("\n\n STATUS: Nenhum erro!! ");
quebrar;
caso 0x01:
cprintf("\n\n STATUS: Comando incorreto ");
quebrar;
caso 0x02:
cprintf("\n\n STATUS: Marca de endereço não encontrada ");
quebrar;
caso 0x03:
cprintf("\n\n STATUS: Tentativa de gravar em disco protegido contra gravação ");
quebrar;
caso 0x04:
cprintf("\n\n STATUS: Setor não encontrado ");
quebrar;
caso 0x06:
cprintf("\n\n STATUS: Disco alterado desde a última operação ");
quebrar;
caso 0x08:
cprintf("\n\n STATUS: Saturação de acesso direto à memória (DMA) ");
quebrar;
caso 0x09:
cprintf("\n\n STATUS: Tentativa de executar DMA através do limite de 64K ");
quebrar;
caso 0x0C:
cprintf("\n\n STATUS: Tipo de mídia não encontrado ");
quebrar;
caso 0x10:
cprintf("\n\n STATUS: CRC/ECC inválido na leitura do disco ");
quebrar;
caso 0x20:
cprintf("\n\n STATUS: O controlador falhou ");
quebrar;
caso 0x31:
cprintf("\n\n STATUS: Nenhuma mídia na unidade (extensões IBM/MS INT 13H) ");
quebrar;
caso 0x32:
cprintf("\n\n STATUS: Tipo de unidade incorreto armazenado no CMOS (Compaq) ");
quebrar;
caso 0x40:
cprintf("\n\n STATUS: Falha na operação de busca ");
quebrar;
caso 0x80:
cprintf("\n\n STATUS: O anexo falhou ao responder (Tempo limite do disco esgotado) ");
quebrar;
caso 0xB0:
cprintf("\n\n STATUS: Volume não bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB1:
cprintf("\n\n STATUS: Volume bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB2:
cprintf("\n\n STATUS: Volume não removível (extensões INT 13H) ");
quebrar;
caso 0xB3:
cprintf("\n\n STATUS: Volume em uso (INT 13H extensões) ");
quebrar;
caso 0xB4:
cprintf("\n\n STATUS: Contagem de bloqueios excedida (INT 13H extensões) ");
quebrar;
caso 0xB5:
cprintf("\n\n STATUS: Falha na solicitação de ejeção válida (INT 13H extensões) ");
quebrar;
padrão: cprintf("\n\n STATUS: CÓDIGO de status DESCONHECIDO para erros de disquete ");
}
}
retornar 0;
}
Comentários sobre a codificação do programa:
Na codificação do programa fornecida anteriormente, basicamente estamos procedendo para executar as seguintes tarefas passo a passo:
- dinfo aponta para a estrutura diskinfo_t que contém as informações dos parâmetros necessários para a operação realizada pela função _bios_disk.
- Como queremos ler o primeiro setor do disco, a localização do setor será a seguinte:
Parâmetro |
O que isso significa |
dinfo.drive = 0x00 |
Indica a unidade 0 que é a unidade de disquete ( a :) |
dinfo.cabeça = 0 |
Aponta para a cabeça número 0 |
dinfo.track = 0 |
Ele aponta para a trilha 0 |
dinfo.setor = 1 |
Primeiro setor do disquete que é o setor 1 |
dinfo.setor = 1 |
Número de setores a serem considerados para operação de leitura = 1 |
dinfo.buffer = dbuf |
Buffer de dados para a operação |
- Abra um fluxo de arquivo com nome de arquivo e caminho fornecidos pelo usuário para armazenar as informações da imagem de boot de exatos 512 bytes. O nome do arquivo e o caminho são armazenados no array de caracteres fname.
- Inicialize o sistema de disco usando a interrupção 13H (função 00h) onde regs.h.ah = 0x00 aponta para a função 00 H e regs.h.dl = 0x00 é usado para a: floppy. E int86(0x13, ®s, ®s) invoca o serviço de interrupção do MS-DOS INT 13 H.
- _bios_disk(_DISK_READ, &dinfo) lê o setor especificado do disquete.
- O status retornado é armazenado no resultado que é usado para exibir a mensagem de operação bem-sucedida ou para exibir uma mensagem de erro na tela caso ocorra algum erro.

Colando a imagem de boot no primeiro setor de um disquete ilegível
Para colar a imagem de boot do arquivo para o primeiro setor do disquete ilegível, temos que executar as três tarefas principais a seguir em nosso programa:
- Lê informações exatas de 512 bytes do registro de inicialização do disquete novo do arquivo salvo anteriormente.
- Grave esta informação no primeiro setor do disquete que está ilegível no momento.
- Verifique a conclusão bem-sucedida da operação de gravação (mais importante).
Como o setor do disquete tem 512 bytes e é necessário colar a imagem de boot exata no setor. É o passo mais importante e necessário no caso de qualquer tipo de operação aplicada no disquete para verificar se a operação foi bem-sucedida ou não.
Pode haver algum problema de inicialização com o disquete durante a operação, portanto você deve inicializar o disco reiniciando o sistema de disco (usando a função 00H do INT 13H).
Se, mesmo após a inicialização, o disquete inserido recentemente ou o disquete alterado causar algum erro de leitura , é recomendável executar o programa novamente, pois provavelmente ele funcionará desta vez.
O programa a seguir é para executar essas tarefas especificadas. Vamos ver como ele procede:
/* Carregar imagem de boot para o disquete ilegível */
#incluir <bios.h>
#incluir <stdio.h>
int principal(vazio)
{
estrutura diskinfo_t dinfo;
sindicato REGS regs;
int resultado;
int contagem=0, i;
char fname[80];
char dbuf[512];
ARQUIVO *fp;
clrscr();
gotoxy(5,3);cprintf("Digite o nome do arquivo e o caminho no qual a imagem de inicialização do disquete está armazenada");
gotoxi(5,5);
obtém(fname);
fp=fopen(nomef,"rb");
se((fp=fopen(fname,"rb"))==NULL)
{
vídeo alto();
gotoxy(10,10);cprintf("O arquivo não pôde ser aberto");
obter();
saída(0);
}
gotoxi(10,9);
cprintf("Tentando recuperar unidade de disquete :\n");
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
enquanto(contagem<512)
{
fscanf(fp,"%c",&dbuf[contagem]);
contar++;
}
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = 0; /* número da cabeça do disco */
dinfo.track = 0; /* número da trilha */
dinfo.sector = 1; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
resultado = _bios_disk(_DISK_WRITE, &dinfo);
se ((resultado & 0xff00) == 0)
{
fclose(fp);
gotoxy(10,14);cprintf("Bem-sucedido!!! Espero que o Floppy possa
Trabalhe agora.\n");
}
outro
{
gotoxi(10,14);
cprintf("Não é possível ler a unidade A, status = 0x%02x\n",result);
gotoxi(10,16);
switch(resultado)
{
caso 0x00:
cprintf("\n\n STATUS: Nenhum erro!! ");
quebrar;
caso 0x01:
cprintf("\n\n STATUS: Comando incorreto ");
quebrar;
caso 0x02:
cprintf("\n\n STATUS: Marca de endereço não encontrada ");
quebrar;
caso 0x03:
cprintf("\n\n STATUS: Tentativa de gravar em disco protegido contra gravação ");
quebrar;
caso 0x04:
cprintf("\n\n STATUS: Setor não encontrado ");
quebrar;
caso 0x06:
cprintf("\n\n STATUS: Disco alterado desde a última operação ");
quebrar;
caso 0x08:
cprintf("\n\n STATUS: Saturação de acesso direto à memória (DMA) ");
quebrar;
caso 0x09:
cprintf("\n\n STATUS: Tentativa de executar DMA através do limite de 64K ");
quebrar;
caso 0x0C:
cprintf("\n\n STATUS: Tipo de mídia não encontrado ");
quebrar;
caso 0x10:
cprintf("\n\n STATUS: CRC/ECC inválido na leitura do disco ");
quebrar;
caso 0x20:
cprintf("\n\n STATUS: O controlador falhou ");
quebrar;
caso 0x31:
cprintf("\n\n STATUS: Nenhuma mídia na unidade (extensões IBM/MS INT 13H) ");
quebrar;
caso 0x32:
cprintf("\n\n STATUS: Tipo de unidade incorreto armazenado no CMOS (Compaq) ");
quebrar;
caso 0x40:
cprintf("\n\n STATUS: Falha na operação de busca ");
quebrar;
caso 0x80:
cprintf("\n\n STATUS: O anexo falhou ao responder (Tempo limite do disco esgotado) ");
quebrar;
caso 0xB0:
cprintf("\n\n STATUS: Volume não bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB1:
cprintf("\n\n STATUS: Volume bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB2:
cprintf("\n\n STATUS: Volume não removível (extensões INT 13H) ");
quebrar;
caso 0xB3:
cprintf("\n\n STATUS: Volume em uso (INT 13H extensões) ");
quebrar;
caso 0xB4:
cprintf("\n\n STATUS: Contagem de bloqueios excedida (INT 13H extensões) ");
quebrar;
caso 0xB5:
cprintf("\n\n STATUS: Falha na solicitação de ejeção válida (INT 13H extensões) ");
quebrar;
padrão: cprintf("\n\n STATUS: CÓDIGO de status DESCONHECIDO para erros de disquete ");
}
}
retornar 0;
}
Comentários sobre a codificação do programa:
Na codificação do programa fornecida anteriormente, basicamente estamos procedendo para executar as seguintes tarefas passo a passo:
- dinfo aponta para a estrutura diskinfo_t que contém as informações dos parâmetros necessários para a operação realizada pela função _bios_disk.
- Como vamos escrever as informações no primeiro setor do disco, a localização do setor será a seguinte:
- Abra o arquivo no qual as informações da imagem de boot de 512 bytes de um disquete novo foram armazenadas pelo programa anterior. O nome do arquivo e o caminho são armazenados no array de caracteres fname.
- Inicialize o sistema de disco usando a interrupção 13H (função 00h) onde regs.h.ah = 0x00 aponta para a função 00 H e regs.h.dl = 0x00 é usado para a: floppy. E int86(0x13, ®s, ®s) invoca o serviço de interrupção do MS-DOS INT 13 H.
- _bios_disk(_DISK_WRITE, &dinfo) grava as informações de inicialização do arquivo especificado no primeiro setor (especificado) do disquete.
- O status retornado é armazenado no resultado que é usado para exibir a mensagem de operação bem-sucedida ou para exibir uma mensagem de erro na tela caso ocorra algum erro.
Parâmetro |
O que isso significa |
dinfo.drive = 0x00 |
Indica a unidade 0 que é a unidade de disquete ( a :) |
dinfo.cabeça = 0 |
Aponta para a cabeça número 0 |
dinfo.track = 0 |
Ele aponta para a trilha 0 |
dinfo.setor = 1 |
Primeiro setor do disquete que é o setor 1 |
dinfo.setor = 1 |
Número de setores a serem considerados para operação de gravação = 1 |
dinfo.buffer = dbuf |
Buffer de dados para a operação |
Vamos fazer isso com um único programa
Espero que agora você tenha entendido o conceito por trás desse tipo de recuperação de dados do disquete . Depois disso, vamos imaginar um único programa que dá os mesmos resultados que obtivemos com a ajuda dos dois programas discutidos anteriormente.
Estávamos realizando as seguintes tarefas com os programas discutidos recentemente:
- Armazene as informações de inicialização de um disquete em bom estado em um arquivo
- Cole essas informações no primeiro setor do disquete atualmente ilegível. O arquivo que estávamos usando para armazenar a imagem de boot estava funcionando como uma ponte intermediária para conectar as operações de ambos os programas. Mas se definirmos essas informações de boot na codificação do nosso programa, não precisamos criar um arquivo, assim como não precisamos ler as informações de boot do disquete a partir do arquivo.
No nosso próximo programa, estamos dizendo ao nosso programa o que ele precisa gravar no primeiro setor do disquete ilegível e, assim, podemos evitar que dois programas diferentes façam a mesma tarefa e podemos recuperar nossos dados da mesma forma que antes, a partir do novo programa único.
O programa então se torna simples com menos codificação e somos capazes de reduzir a probabilidade de ocorrência de erros de leitura, escrita ou criação de arquivos . Estamos fazendo as quatro tarefas importantes a seguir neste programa:
Não pense que o programa é difícil de escrever e entender ao ver as informações hexadecimais de 512 bytes de dbuf[512]. Mais tarde, discutiremos a maneira fácil de escrever essas informações para a codificação do seu programa.
- Defina as informações do registro de inicialização do DOS no sistema hexadecimal para serem gravadas no primeiro setor do disquete atualmente ilegível.
- Reinicie o sistema de disco para inicializar o disquete (INT 13H, Função 00H).
- Grave o DOS Boot Record no primeiro setor do disquete
- Verifique se a operação foi concluída com sucesso e se ocorreu algum erro.
Vamos examinar o programa:
/* Programa único para carregar a imagem de inicialização padrão em um disquete ilegível */
#incluir <bios.h>
#incluir <stdio.h>
int principal(vazio)
{
estrutura diskinfo_t dinfo;
sindicato REGS regs:
int resultado, i;
/* Imagem de inicialização a ser carregada na unidade de disquete */
char estático dbuf[512]=
{
0xEB,0x3E,0x90,0x2B,0x29,0x6E, 0x70,0x32,0x49,0x48,0x43,0x0,0x2,0x1,0x1,0x0,
0x2,0xE0,0x0,0x40,0xB,0xF0,0x9,0x0,0x12, 0x0 ,0x2 ,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x29, 0x24,0x3B,0xDB, 0x16,0x4E, 0x4F, 0x20, 0x4E,0x41,0x4D,0x45,
0x20, 0x20, 0x20,0x20,0x46,0x41, 0x54,0x31, 0x32,0x20,0x20, 0x20,0xF1,0x7D, 0xFA,
0x33, 0xC9,0x8E,0xD1, 0xBC,0xFC,0x7B, 0x16,0x7 ,0xBD,0x78,0x0 ,0xC5,0x76,0x0,
0x1E,0x56,0x16,0x55, 0xBF,0x22,0x5,0x89,0x7E,0x0,0x89,0x4E,0x2,0xB1,0xB,0xFC,
0xF3,0xA4,0x6,0x1F,0xBD,0x0,0x7C,0xC6,0x45,0xFE,0xF,0x8B, 0x46,0x18,0x88,0x45,
0xF9,0xFB,0x38,0x66, 0x24,0x7C,0x4,0xCD,0x13, 0x72,0x3C,0x8A,
0x46,0x10,0x98,0xF7,
0x66,0x16,0x3, 0x46,0x1C,0x13,0x56, 0x1E,0x3 ,0x46,0xE,0x13,
0xD1,0x50,0x52,0x89,
0x46,0xFC,0x89, 0x56,0xFE,0xB8,0x20,0x0, 0x8B,0x76,0x11,0xF7,
0xE6,0x8B,0x5E,0xB ,
0x3,0xC3,0x48,0xF7,0xF3,0x1,0x46,0xFC, 0x11,0x4E,0xFE,0x5A,
0x58,0xBB,0x0 ,0x7 ,
0x8B,0xFB,0xB1,0x1, 0xE8,0x94,0x0 ,0x72,0x47,0x38,0x2D,0x74, 0x19,0xB1,0xB,0x56,
0x8B,0x76,0x3E, 0xF3,0xA6,0x5E,0x74,0x4A,0x4E, 0x74,0xB,0x3 , 0xF9,0x83, 0xC7, 0x15,
0x3B, 0xFB, 0x72, 0xE5, 0xEB, 0xD7, 0x2B, 0xC9, 0xB8, 0xD8, 0x7D, 0x87, 0x46, 0x3E, 0x3C,
0xD8,0x75,0x99, 0xBE,0x80,0x7D,0xAC, 0x98,0x3,0xF0,0xAC,0x84 ,0xC0,0x74,0x17,0x3C,
0xFF,0x74,0x9,0xB4,0xE,0xBB,0x7,0x0,0xCD,0x10,0xEB, 0xEE,0xBE,0x83,0x7D, 0xEB,
0xE5, 0xBE, 0x81,0x7D, 0xEB,0xE0, 0x33,0xC0,0xCD,0x16,0x5E,0x1F,0x8F,0x4,0x8F,0x44,
0x2,0xCD, 0x19,0xBE,0x82,0x7D,0x8B,0x7D,0xF, 0x83,0xFF,0x2,0x72,0xC8, 0x8B,0xC7,0x48,
0x48,0x8A,0x4E,0xD,0xF7,0xE1,0x3,0x46,0xFC, 0x13,0x56,0xFE,0xBB,0x0,0x7,0x53,0xB1,0x4,
0xE8,0x16,0x0, 0x5B,0x72,0xC8, 0x81,0x3F,0x4D,0x5A, 0x75,0xA7,0x81,0xBF, 0x0,0x2,0x42,0x4A,
0x75,0x9F,0xEA,0x0 ,0x2 ,0x70,0x0,0x50,0x52, 0x51, 0x91, 0x92, 0x33, 0xD2,0xF7,0x76,0x18,0x91,
0xF7,0x76, 0x18,0x42, 0x87, 0xCA, 0xF7, 0x76,0x1A,0x8A,0xF2,0x8A,0x56, 0x24,0x8A,0xE8,
0xD0, 0xCC,0xD0,0xCC,0xA, 0xCC,0xB8,0x1,0x2, 0xCD,0x13,0x59,0x5A, 0x58, 0x72,0x9,0x40,
0x75,0x1,0x42,0x3, 0x5E,0xB,0xE2,0xCC,0xC3,0x3,0x18,0x1,0x27,0xD,0xA,0x49, 0x6E,
0x76,0x61,0x6C,0x69,0x64,0x20, 0x73, 0x79, 0x73, 0x74, 0x65,0x6D,0x20,0x64,0x69,0x73,
0x6B,0xFF,0xD,0xA,0x44,0x69, 0x73,0x6B,0x20, 0x49,0x2F, 0x4F,0x20, 0x65,0x72, 0x72,0x6F,
0x72,0xFF,0xD,0xA,0x52, 0x65,0x70,0x6C,0x61,0x63, 0x65,0x20,
0x74,0x68,0x65,0x20,
0x64, 0x69,0x73, 0x6B,0x2C,0x20,0x61, 0x6E,0x64,0x20,0x74, 0x68, 0x65, 0x6E, 0x20,0x70,
0x72,0x65, 0x73,0x73, 0x20,0x61, 0x6E,0x79,0x20,0x6B,0x65,0x79,0xD,0xA, 0x0,0x49,0x4F,
0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x53,0x59,0x53,0x4D, 0x53, 0x44, 0x4F, 0x53,0x20,0x20,
0x20,0x53, 0x59,0x53, 0x80,0x1,0x0 ,0x57,0x49, 0x4E,0x42, 0x4F,0x4F,0x54,0x20,0x53, 0x59
,0x53,0x0,0x0,0x55,0xAA};
clrscr();
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = 0; /* número da cabeça do disco */
dinfo.track = 0; /* número da trilha */
dinfo.sector = 1; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
gotoxi(10,9);
cprintf("Tentando ler da unidade de disquete :\n");
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
resultado = _bios_disk(_DISK_WRITE, &dinfo);
se ((resultado & 0xff00) == 0)
{
gotoxi(10,14);
cprintf("Status de gravação do disco: bem-sucedido.\n");
}
outro
{
gotoxi(10,14);
cprintf("Não é possível ler a unidade A, status = 0x%02x\n",
resultado);
gotoxi(10,16);
switch(resultado)
{
caso 0x00:
cprintf("\n\n STATUS: Nenhum erro!! ");
quebrar;
caso 0x01:
cprintf("\n\n STATUS: Comando incorreto ");
quebrar;
caso 0x02:
cprintf("\n\n STATUS: Marca de endereço não encontrada ");
quebrar;
caso 0x03:
cprintf("\n\n STATUS: Tentativa de escrever para escrever-
disco protegido ");
quebrar;
caso 0x04:
cprintf("\n\n STATUS: Setor não encontrado ");
quebrar;
caso 0x06:
cprintf("\n\n STATUS: Disco alterado desde a última operação ");
quebrar;
caso 0x08:
cprintf("\n\n STATUS: Saturação de acesso direto à memória (DMA) ");
quebrar;
caso 0x09:
cprintf("\n\n STATUS: Tentativa de executar DMA através do limite de 64K ");
quebrar;
caso 0x0C:
cprintf("\n\n STATUS: Tipo de mídia não encontrado ");
quebrar;
caso 0x10:
cprintf("\n\n STATUS: CRC/ECC inválido na leitura do disco ");
quebrar;
caso 0x20:
cprintf("\n\n STATUS: O controlador falhou ");
quebrar;
caso 0x31:
cprintf("\n\n STATUS: Nenhuma mídia na unidade (extensões IBM/MS INT 13H) ");
quebrar;
caso 0x32:
cprintf("\n\n STATUS: Tipo de unidade incorreto armazenado no CMOS (Compaq) ");
quebrar;
caso 0x40:
cprintf("\n\n STATUS: Falha na operação de busca ");
quebrar;
caso 0x80:
cprintf("\n\n STATUS: O anexo falhou ao responder (Tempo limite do disco esgotado) ");
quebrar;
caso 0xB0:
cprintf("\n\n STATUS: Volume não bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB1:
cprintf("\n\n STATUS: Volume bloqueado na unidade (extensões INT 13H) ");
quebrar;
caso 0xB2:
cprintf("\n\n STATUS: Volume não removível (extensões INT 13H) ");
quebrar;
caso 0xB3:
cprintf("\n\n STATUS: Volume em uso (INT 13 extensões) ");
quebrar;
caso 0xB4:
cprintf("\n\n STATUS: Contagem de bloqueios excedida (INT 13H extensões) ");
quebrar;
caso 0xB5:
cprintf("\n\n STATUS: Falha na solicitação de ejeção válida (INT 13H extensões) ");
quebrar;
padrão: cprintf("\n\n STATUS: CÓDIGO de status DESCONHECIDO para erros de disquete ");
}
}
retornar 0;
}
Nesta codificação de programa, basicamente iremos executar as seguintes tarefas passo a passo:
- O buffer de dados de caracteres estáticos dbuf[512] fornece as informações de 512 bytes no sistema hexadecimal, que devem ser gravadas no primeiro setor do disquete ilegível. dbuf[512] informa ao computador durante a operação quais informações devem ser gravadas no primeiro setor do disquete. (Veja o próximo programa)
- dinfo aponta para a estrutura diskinfo_t que contém as informações dos parâmetros necessários para a operação realizada pela função _bios_disk.
- Como vamos escrever as informações no primeiro setor do disco, a localização do setor será a seguinte:
Parâmetro |
O que isso significa |
dinfo.drive = 0x00 |
Indica a unidade 0 que é a unidade de disquete ( a :) |
dinfo.cabeça = 0 |
Aponta para a cabeça número 0 |
dinfo.track = 0 |
Ele aponta para a trilha 0 |
dinfo.setor = 1 |
Primeiro setor do disquete que é o setor 1 |
dinfo.setor = 1 |
Número de setores a serem considerados para operação de gravação = 1 |
dinfo.buffer = dbuf |
Buffer de dados para a operação |
- Inicialize o sistema de disco usando a interrupção 13H (função 00h) onde regs.h.ah = 0x00 aponta para a função 00 H e regs.h.dl = 0x00 é usado para a: floppy. E int86(0x13, ®s, ®s) invoca o serviço de interrupção do MS-DOS INT 13 H.
- _bios_disk(_DISK_WRITE, &dinfo) grava as informações de inicialização do arquivo especificado no primeiro setor (especificado) do disquete.
O status retornado é armazenado no resultado que é usado para exibir a mensagem de operação bem-sucedida ou para exibir uma mensagem de erro na tela caso ocorra algum erro.
Armazenando a imagem de inicialização em caracteres HEXADECIMAL para usar em nosso programa anterior
Será um trabalho muito difícil escrever todos os 512 caracteres do DOS Boot Record do disquete manualmente no sistema hexadecimal sem nenhum erro no programa que discutimos recentemente. Se pudermos escrever com precisão, mesmo assim será uma tarefa difícil e demorada. Vamos usar um pouco de mente complicada para armazenar os dados do buffer de dados dbuf[512] em um arquivo.
Sabemos que na programação C os caracteres hexadecimais são representados com 0x, de modo que se o caractere hexadecimal for A9 H, escreveremos isso em nosso programa C como 0xA9. Nosso próximo programa está fazendo o mesmo. Ele armazenará os dados que precisamos escrever em nosso programa anterior, como os dados do buffer de dados dbuf[512].
O que você tem que fazer é pegar um disquete novo e fresco para fazer a imagem do seu DBR e copiar a saída deste programa do arquivo de destino especificado e colar esses dados no seu programa. Faça alguma formatação, se necessário. Vamos ver como funciona:
/* Programa para fazer a imagem de boot do disquete em caracteres HEX */
#incluir <bios.h>
#incluir <stdio.h>
int principal(vazio)
{
estrutura diskinfo_t dinfo;
sindicato REGS regs;
int resultado,i;
int contagem=0;
char fname[80];
char estático dbuf[512];
ARQUIVO *fp;
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = 0; /* número da cabeça do disco */
dinfo.track = 0; /* número da trilha */
dinfo.sector = 1; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
clrscr();
gotoxy(10,3);cprintf("Digite o nome do arquivo e o caminho para
Armazene a imagem de inicialização no sistema HEX");
gotoxi(5,5);
obtém(fname);
fp=fopen(nomef,"wb");
se((fp=fopen(fname,"wb"))==NULL)
{
vídeo alto();
gotoxy(10,10);cprintf("O arquivo não pôde ser criado");
obter();
saída(0);
}
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
gotoxy(10,9); cprintf("Tentando ler do disquete
unidade de disco :\n");
resultado = _bios_disk(_DISK_READ, &dinfo);
se ((resultado & 0xff00) == 0)
{
gotoxi(10,14);
cprintf("Disco lido da unidade de disquete:
bem-sucedido.\n");
enquanto(contagem<512)
{
fprintf(fp,"0x%X, ",dbuf[contagem] & 0xff );
contar++;
}
fclose(fp);
}
outro
{
gotoxi(10,14);
cprintf("Não é possível ler a unidade A, status = 0x%02x\n",
resultado);
}
retornar 0;
}
Comentários sobre a codificação do programa:
Assim, os dados são armazenados no arquivo especificado. Apenas copie os dados para o seu programa e faça alguma formatação necessária. Você nunca deve esquecer as seguintes dicas durante o procedimento:
- Certifique-se de que a operação do programa foi bem-sucedida e que os dados armazenados no arquivo de destino são apropriados.
- Você deve verificar a operação para verificar a ocorrência de erros esperados.
- Você deve inicializar o disquete em, com o programa antes de ler seu setor de boot. Você pode usar a função 00H do INT 13H para esse propósito.
Método – 2
O que fazer se o Método – 1 não funcionar?
Se o Método – 1 não funcionar e o disco ilegível não estiver permitindo que o programa reescreva as informações de inicialização em seu primeiro setor, você deve tentar este segundo método. A razão por trás da falha do Primeiro Método pode ser a corrupção física do primeiro setor do disquete.
Neste segundo método, copiaremos todos os dados da superfície do disquete ilegível para um único arquivo temporariamente e então colaremos esta imagem diretamente na superfície do outro disco bom.
O procedimento envolve as duas etapas importantes a seguir:
- Copie, setor por setor, todos os dados da superfície da mídia do disquete para um único arquivo temporariamente.
- Cole os dados armazenados anteriormente no arquivo em um novo disquete, como ele está, nos mesmos setores.
Copie todos os dados da superfície da mídia para um único arquivo
Para armazenar todos os dados da superfície da mídia do disquete, o programa deve executar as três tarefas a seguir:
- Inicialize o disco corretamente com a ajuda da função 00H do INT 13H.
- Leia as informações setor por setor da superfície e armazene em um único arquivo.
- Verifique se a operação de leitura foi bem-sucedida (mais importante)
É muito comum ter qualquer problema de inicialização com um disquete que leva a muitas mensagens de leitura malsucedidas. É por isso que o disco deve ser inicializado antes da operação de leitura e gravação com a ajuda da programação.
A etapa mais importante e necessária no caso de qualquer tipo de operação aplicada no disquete é verificar se a operação foi bem-sucedida ou não.
Se, mesmo após a inicialização, o disquete inserido recentemente ou o disquete alterado causar algum erro de leitura, é recomendável executar o programa novamente, pois provavelmente ele funcionará desta vez.
O programa a seguir é para executar essas tarefas especificadas. Vamos ver como ele procede:
/* Programa para armazenar os dados da superfície física do disquete em um arquivo */
#incluir <bios.h>
#incluir <stdio.h>
vazio principal(vazio)
{
int cabeça,trilha;
sindicato REGS regs;
int resultado,i,setor;
char nomedoarquivo[80];
estrutura diskinfo_t dinfo;
char estático dbuf[512];
ARQUIVO *tt;
clrscr();
printf("\n Digite o nome do arquivo com o caminho para armazenar o
Dados Temporariamente\n");
obtém(nome do arquivo);
if((tt=fopen(nome do arquivo,"wb"))==NULL)
{
printf("Não foi possível criar o arquivo,
Pressione qualquer tecla para SAIR");
obter();
saída(0);
}
printf("\n Inicializando o sistema de disquete...\n");
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
para(trilha=0;trilha<=79;trilha++)
{
para(cabeça=0;cabeça<=1;cabeça++)
{
para(setor=1;setor<=18;setor++)
{
dinfo.drive = 0; /* número da unidade para A: */
dinfo.head = head; /* número da cabeça do disco */
dinfo.track = track; /* número da faixa */
dinfo.sector = setor; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
resultado = _bios_disk(_DISK_READ, &dinfo);
se ((resultado & 0xff00) == 0)
{
para(i=0;i<512;i++)
fprintf(tt,"%c",dbuf[i] & 0xff);
}
outro
{
printf("Não é possível ler a unidade A, status =
0x%02x\t%d\t%d\t%d\n", resultado,cabeçalho,trilha,setor);
}
printf("Faixa de leitura= %d Cabeçalho= %d Setor= %d\n",
trilha,cabeça,setor);
}
}
}
}
Comentários sobre a codificação do programa:
Na codificação do programa fornecida anteriormente, basicamente estamos procedendo para executar as seguintes tarefas passo a passo:
- O array de caracteres filename[80] armazena o caminho definido pelo usuário e o nome do arquivo no qual iremos armazenar os dados temporariamente.
- dinfo aponta para a estrutura diskinfo_t que contém as informações dos parâmetros necessários para a operação realizada pela função _bios_disk.
- Inicialize o sistema de disco usando a interrupção 13H (função 00h) onde regs.h.ah = 0x00 aponta para a função 00 H e regs.h.dl = 0x00 é usado para a: floppy. E int86(0x13, ®s, ®s) invoca o serviço de interrupção do MS-DOS INT 13 H.
- Como vamos ler todas as informações da superfície do disco, os parâmetros do _bios_disk serão os seguintes:
Parâmetro |
O que isso significa |
dinfo.drive = 0x00 |
Indica a unidade 0 que é a unidade de disquete ( a :) |
dinfo.head = cabeça |
Ele aponta para a cabeça número 0 e 1, pois o disquete tem dois lados (duas cabeças) |
dinfo.track = trilha |
Ele aponta para a faixa de 0 a 79, pois há 80 faixas em cada lado do disquete. |
dinfo.sector = setor |
Ele aponta para o setor 1 a 18, pois há 18 setores em cada trilha. |
dinfo.setor = 1 |
Número de setores a serem considerados para operação de leitura = 1 |
dinfo.buffer = dbuf |
Buffer de dados para a operação |
- _bios_disk(_DISK_READ, &dinfo) lê os dados da superfície física do disquete do setor especificado por dinfo.
- O status retornado é armazenado no resultado que é usado para exibir a mensagem de operação bem-sucedida ou para exibir uma mensagem de erro na tela caso ocorra algum erro.
Lembre-se sempre que o tamanho do arquivo que contém a imagem dos dados do disquete deve ser exato 1.474.560 bytes porque o disquete tem 80 trilhas (0 a 79), 2 lados ou cabeças (cabeça 0 e cabeça 1), cada trilha tem 18 setores e cada setor contém 512 bytes de dados, portanto
Total de bytes = (Número de trilhas) * (Número de cabeças) *
(Número de setores por trilha) * 512
= 80*2*18*512
= 1.474.560 bytes
Assim, se houver algum erro na leitura de qualquer setor do disquete, o tamanho do arquivo será alterado de 1.474.560 Bytes, o que tornará toda a informação total ou parcialmente inútil para o disco de destino no qual iremos gravar a imagem de disco setor por setor deste arquivo.
Isso ocorre porque o computador lê as informações de qualquer arquivo na superfície da mídia do disquete dentro do intervalo de setores, conforme foi alocado em sua unidade de alocação. Agora, se os setores dos dados dos arquivos forem alterados, as informações completas do arquivo serão alteradas.
Pensando na solução do erro de leitura do(s) setor(es)
É possível que um disquete ruim ou ilegível tenha uma área tão ruim em sua superfície que não consigamos ler as informações da superfície do disco.
Nessa condição as informações desse(s) setor(es) serão puladas e a imagem do disquete ficará distorcida até mesmo para os outros setores, pois o tamanho do arquivo de imagem nesse caso difere de 1.474.560 Bytes.
Para manter o tamanho do arquivo de imagem e colar o restante das informações nos locais exatos dos setores no disco de destino, escrevemos algumas outras informações em nome dos dados originais de 512 bytes e, dessa forma, seremos capazes de salvar o restante das informações, porém a recuperação nesse caso pode ser uma recuperação parcial.
Se o seu sistema também não conseguir ler o primeiro setor do disquete de origem, depois de colar a imagem no disquete de destino, você deve executar o programa descrito anteriormente para reescrever o Registro de Inicialização DOS do disquete.
Vamos ver como podemos fazer isso programando:
#incluir <bios.h>
#incluir <stdio.h>
vazio principal(vazio)
{
int cabeça,trilha;
sindicato REGS regs;
int resultado,i,setor;
char nomedoarquivo[80];
estrutura diskinfo_t dinfo;
char estático dbuf[512];
/* Informação de 512 Bytes para preencher o espaço do Setor Defeituoso */
/// Usei 512 zeros para preencher o espaço de 512 bytes \\\
char estático dbuf2[512] =
"00000000000000000000000000000" "000000000000000000000000000000" "000000000000000000000000000000" "00000000000000000000000000000" "000000000000000000000000000000" "000000000000000000000000000000" "00000000000000000000000000000" "00000000000000000000000000000" "000000000000000000000000000000" "000000000000000000000000000000" "00000000000000000000000000000" "000000000000000000000000000000" "000000000000000000000000000000" "00000000000000000000000000000" "000000000000000000000000000000" "000000000000000000000000000000";
ARQUIVO *tt;
clrscr();
printf("\n Digite o nome do arquivo com o caminho para armazenar o
Dados Temporariamente\n");
obtém(nome do arquivo);
if((tt=fopen(nome do arquivo,"wb"))==NULL)
{
printf("Não foi possível criar o arquivo, pressione qualquer tecla para
SAÍDA");
obter();
saída(0);
}
printf("\n Inicializando o sistema de disquete...\n");
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
para(trilha=0;trilha<=79;trilha++)
{
para(cabeça=0;cabeça<=1;cabeça++)
{
para(setor=1;setor<=18;setor++)
{
dinfo.drive = 0; /* número da unidade para A: */
dinfo.head = head; /* número da cabeça do disco */
dinfo.track = track; /* número da faixa */
dinfo.sector = setor; /* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
resultado = _bios_disk(_DISK_READ, &dinfo);
se ((resultado & 0xff00) == 0)
{
para(i=0;i<512;i++)
fprintf(tt,"%c",dbuf[i] & 0xff);
}
outro
{
printf("Não é possível ler a unidade A, status =
0x%02x\t%d\t%d\t%d\n", resultado, cabeça, trilha, setor);
/* Se o setor não for legível, ocupe 512 bytes por dbuf2 */
fwrite(dbuf2,512,1,tt);
}
printf("Faixa de leitura= %d Cabeçalho= %d Setor= %d\n",
trilha, cabeça, setor);
}
}
}
}
Comentários sobre a codificação do programa:
Na codificação do programa, cada etapa é igual à do programa anterior, exceto o buffer de dados dbuf2[512], que estamos usando para lidar com o erro gerado pelo setor defeituoso durante a operação de leitura do disco e para manter o tamanho do arquivo de imagem.
Ao fazer isso, estamos preenchendo o espaço da informação que não conseguimos ler do setor defeituoso e agora estamos gravando a pseudoinformação de 512 bytes para que possamos manter a precisão da imagem do disco.
Cole os dados do arquivo na superfície física do disquete novo:
Nesta etapa, colamos os dados armazenados no arquivo pelo programa anterior, na superfície física do disquete novo, setor por setor, da mesma forma que os copiamos para o arquivo.
O programa prossegue com as seguintes etapas principais:
- Abra o arquivo no qual armazenamos temporariamente os dados de superfície do disquete ilegível.
- Inicialize o sistema de disco corretamente redefinindo a função 00H do INT 13H.
- Escreva as informações sobre os setores do disquete novo do arquivo.
- Exiba o status de gravação simultaneamente para encontrar ou evitar a ocorrência de erros.
O código fonte do programa foi fornecido abaixo. Vamos examinar como ele funciona:
/* Programa para escrever os dados nos setores da superfície do disquete novo a partir do arquivo criado pelo programa anterior */
#incluir <bios.h>
#incluir <stdio.h>
vazio principal(vazio)
{
int cabeça,trilha;
sindicato REGS regs;
int resultado,i,setor;
int contagem =0;
char nomedoarquivo[80];
estrutura diskinfo_t dinfo;
char estático dbuf[512];
ARQUIVO *fp;
clrscr();
printf("\n Digite o nome do arquivo com o caminho para armazenar o
Dados Temporariamente\n");
obtém(nome do arquivo);
if((fp=fopen(nome do arquivo,"rb"))==NULL)
{
printf("Não foi possível criar o arquivo, pressione qualquer tecla para
SAÍDA");
obter();
saída(1);
}
/// Inicializar o sistema de disco \\\
para(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Redefinir sistema de disco */
regs.h.dl = 0x00; /* Disquete a: */
int86(0x13, ®s, ®s);
}
para(trilha=0;trilha<=79;trilha++)
{
para(cabeça=0;cabeça<=1;cabeça++)
{
para(setor=1;setor<=18;setor++)
{
contagem =0;
enquanto(contagem<512)
{
fscanf(fp,"%c",&dbuf[contagem]);
contar++;
}
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = head; /* número da cabeça do disco */
dinfo.track = track; /* número da faixa */
dinfo.sector = setor;/* número do setor */
dinfo.nsectors = 1; /* contagem de setores */
dinfo.buffer = dbuf; /* buffer de dados */
resultado= _bios_disk(_DISK_WRITE, &dinfo);
se ((resultado & 0xff00) == 0)
printf("Gravação bem-sucedida em Track = %d, Head = %d,
Setor = %d.\n", trilha, cabeça, setor);
outro
printf("Não é possível ler a unidade A, status = 0x%02x\n",
resultado);
}
}
}
}
Comentários sobre a codificação do programa:
Na codificação do programa fornecida anteriormente, basicamente estamos procedendo para executar as seguintes tarefas passo a passo:
- O array de caracteres filename[80] contém o caminho e o nome do arquivo no qual armazenamos temporariamente os dados da superfície do disquete ilegível.
- dinfo aponta para a estrutura diskinfo_t que contém as informações dos parâmetros necessários para a operação realizada pela função _bios_disk.
- Inicialize o sistema de disco usando a interrupção 13H (função 00h) onde regs.h.ah = 0x00 aponta para a função 00 H e regs.h.dl = 0x00 é usado para a: floppy. E int86(0x13, ®s, ®s) invoca o serviço de interrupção do MS-DOS INT 13 H.
- Como vamos gravar as informações diretamente em setores da superfície do disco , os parâmetros do _bios_disk serão os seguintes:
Parâmetro |
O que isso significa |
dinfo.drive = 0x00 |
Indica a unidade 0 que é a unidade de disquete ( a :) |
dinfo.head = cabeça |
Ele aponta para a cabeça número 0 e 1, pois o disquete tem dois lados (duas cabeças) |
dinfo.track = trilha |
Ele aponta para a faixa de 0 a 79, pois há 80 faixas em cada lado do disquete. |
dinfo.sector = setor |
Ele aponta para o setor 1 a 18, pois há 18 setores em cada trilha. |
dinfo.setor = 1 |
Número de setores a serem considerados para operação de gravação = 1 |
dinfo.buffer = dbuf |
Buffer de dados para a operação |
- _bios_disk(_DISK_WRITE, &dinfo) grava os dados nos setores da superfície física do disquete, especificados por dinfo.
- O status retornado é armazenado no resultado que é usado para exibir a mensagem de operação bem-sucedida ou para exibir uma mensagem de erro na tela caso ocorra algum erro.
Se após o Método – 2 seu novo disquete não funcionar, você pode aplicar o Método – 1 no seu novo disquete, que você usou como disco de destino durante o Método – 2.
Não só isso, mas também o número de hits e tentativas pode variar dependendo da corrupção do disco. Mas você não precisa se preocupar se mesmo depois não estiver obtendo resultados satisfatórios.
Você pode tentar a recuperação arquivo por arquivo ou pode tentar muitas outras dicas que você aprenderá a seguir. Aqui, implementaremos a ideia de coletar as informações do arquivo dos Diretórios Raiz, em nossa programação para recuperar os dados.
Pensando em recuperação lógica para dados excluídos ou perdidos:
Todos os casos anteriores que discutimos neste capítulo para recuperação foram para recuperar os dados em casos em que esperávamos que apenas o DBR estivesse corrompido e os setores na trilha 0, com diretórios FAT1, FAT2 e Root, fossem legíveis .
Mas se o problema for devido à corrupção do FAT ou os dados foram excluídos do disco ou você deseja recuperar os dados diretamente lendo suas informações do diretório raiz , precisamos ler informações como nome do arquivo , cluster inicial , tamanho do arquivo , atributo etc. de sua entrada no diretório raiz .
Como já discutimos sobre o Root Directory em capítulos anteriores, há informações de 32 bytes para cada arquivo ou diretório. Esses 32 bytes são divididos da seguinte forma:
Número de bytes |
Descrição da informação |
8 bytes |
Nome do arquivo |
3 bytes |
Extensão |
1 Byte |
Atributo |
10 bytes |
Reservado |
2 bytes |
Hora, Criado ou Última Atualização |
2 bytes |
Data, Criado ou Última Atualização |
2 bytes |
Cluster inicial |
4 bytes |
Tamanho do arquivo |
Recuperamos os dados lendo as informações do(s) arquivo(s) do Root Directory e então integramos o arquivo ao caminho de destino e recuperamos o arquivo. Nosso próximo programa executa as seguintes etapas para recuperar os dados:
- Leia as entradas do diretório raiz e exiba-as na tela com todas as informações, como nome do arquivo/diretório, extensão do arquivo, tamanho do cluster inicial dos arquivos em bytes.
- Leia as informações de arquivos e diretórios nos subdiretórios e exiba-as, se necessário.
- Confirme o nome do arquivo a ser recuperado e continue a recuperação.
- Calcule as informações de CHS (Cilindro, Cabeça e Setor) para o arquivo especificado a ser recuperado.
- Integre os dados do arquivo da área de dados do disco e salve o arquivo recuperado no nome de arquivo de destino especificado no caminho especificado.
Este programa não se importa se as informações de inicialização do disquete são legíveis ou não. Portanto, você pode recuperar até mesmo dados excluídos do disquete corrompido também. Vamos ver a codificação do programa:
/* Programa para recuperar dados do disquete lendo informações do arquivo do diretório raiz */
#incluir<stdio.h>
#incluir<bios.h>
#include<dos.h>
vazio principal()
{
void Display_Information(int não assinado,int não assinado,
int sem sinal);
int sem sinal trilha=0,cabeçalho=1,setor=2;
Display_Information(faixa,cabeçalho,setor);
} /*Fim do principal */
void Display_Information(inteiro sem sinal trilha,
cabeça int não assinada,
setor int não assinado)
{
void recuperar(unsigned int *,unsigned int);
char buf[512]; // Buffer de 512 bytes
char ch;
struct diskinfo_t finfo; //Estrutura, usada por _bios_disk
unsigned int result,i,j, count=0; /* Inteiros sem sinal
Definido */
unsigned int file_no; /* Inteiro não assinado
para número de arquivo */
estrutura
{
unsigned int name[8],ext[3]; /* Nome do arquivo para DOS em 8.3
(Oito Pontos Três) Formato */
unsigned int attribute; // Atributo de arquivo/diretório
unsigned int start; // Iniciando o cluster do arquivo
long unsigned int size; // Tamanho do arquivo em bytes
}root[32]; /* 32 Bytes de informação de
Arquivo/Diretório na Raiz
Diretório */
clrscr();
fazer
{
arquivo_no=0;
finfo.drive = 0x00; /* número da unidade para A: */
finfo.head = head; /* número da cabeça do disco */
finfo.track = track; /* número da trilha */
finfo.sector= setor; /* número do setor */
finfo.nsectors=1; /* contagem de setores */
finfo.buffer = buf; /* buffer de dados */
resultado = _bios_disk(_DISK_READ, &finfo); /* Leia o
Setor */
if( (result & 0xff00) != 0) /* Se erro de leitura, exibir
Mensagem de erro e saída*/
{
printf("Erro de leitura");
obter();
exit(0); // Voltar para DOS
}
/// Formato da tela de exibição de informações \\\
clrscr();
gotoxi(9,1);
cprintf("CILINDRO DE EXIBIÇÃO: %u, CABEÇA: %u, SETOR: %u",
trilha, cabeça, setor);
gotoxi(9,2);
cprintf("FNO NOME EXT ATRIBUTO INÍCIO TAMANHO");
gotoxi(7,3);
cprintf("-------------------------------------");
/* Um setor por vez. Cada entrada de arquivo/diretório ocupa 32 bytes */
para(i=0;i<512;i+=32)
{
para(j=0;j<8;j++)
{
/// Encontre o nome do arquivo/diretório \\\
raiz[nº_arquivo].nome[j]=buf[j+i];
}
para(j=8;j<11;j++)
{
/// Encontre a extensão \\\
raiz[nº_arquivo].ext[j-8]=buf[i+j];
}
j=11;
root[file_no].attribute=buf[i+j]; /// Atributo
/// Iniciando Cluster \\\
raiz[número_do_arquivo].início=(0xff & buf[27+i])*16*16 + (0xff & buf[26+i]);
/// Calcular o tamanho \\\
root[file_no].size =(long unsigned int)(0xff &
buf[31+i])*16*16*16*16*16*16*16*16;
root[file_no].size+=(longo int sem sinal)(0xff &
buf[30+i])*16*16*16*16;
root[file_no].size+=(longo int sem sinal)(0xff &
buf[29+i])*16*16;
root[file_no].size+=(longo int sem sinal)(0xff &
buf[28+i]);
se((root[nº_arquivo].início == 0) ||
(root[file_no].attribute == 15))
continuar;
outro
{
gotoxi(8,i/32+4);
cprintf("%2u",file_no); /* Exibir arquivo
Número */
para(j=0;j<8;j++)
{
gotoxi(14+j,i/32+4);
cprintf("%c",root[file_no].name[j]); /* Exibir arquivo
Nome */
}
para(j=0;j<3;j++)
{
gotoxi(26+j,i/32+4);
cprintf("%c",root[file_no].ext[j]); /* Exibir
Extensão */
}
gotoxi(30,i/32+4);
cprintf("%u",root[file_no].attribute); /* Exibir
Atributo */
se(raiz[nº_arquivo].atributo==16)
{
gotoxi(33,i/32+4);
cprintf("<DIR>"); /* Exibir se atributo de diretório */
}
outro
{
gotoxi(33,i/32+4);
cprintf("<FILE>"); /* A entrada é de um arquivo */
}
gotoxi(44,i/32+4);
cprintf("%-5u", root[file_no].start); /* Exibir
Cluster inicial */
gotoxi(58,i/32+4);
cprintf("%-10lu", root[file_no].size); /* tamanho do
Arquivo */
}
arquivo_no++;
}
gotoxi(10,
cprintf("Pressione 'M': Para ver a lista de mais arquivos &quo
gotoxi(10,
cprintf("Pressione 'R': Para recuperar um arquivo do acima
lista&quo
ch=obterc
Lembre-se de que o nome do arquivo que começa com s (E5H) representa que o arquivo foi excluído e, portanto, o primeiro caractere do nome do arquivo foi substituído por s (consulte a descrição do diretório raiz nos capítulos anteriores).
E a saída do programa é exibida assim:
EXIBIR CILINDRO: 0, CABEÇA: 1, SETOR: 2
FNO NOME EXT ATRIBUTO INÍCIO TAMANHO
-----------------------------------------------------------------------------------------
0 WE 32 <ARQUIVO> 15 1800
1 s2_INFO C 32 <ARQUIVO> 5 4700
2 THELP CFG 32 <ARQUIVO> 2 22
3 THELP COM 32 <ARQUIVO> 3 11072
4 TIMEIT CPP 32 <ARQUIVO> 39 1186
5 TOUCH COM 32 <ARQUIVO> 42 5124
6 TRY1 CPP 32 <ARQUIVO> 53 1581
7 TURBOC CFG 32 <ARQUIVO> 57 30
8 AA CPP 32 <ARQUIVO> 58 260
9 ABC CPP 32 <ARQUIVO> 59 1036
10 ASSIGN1 CPP 32 <ARQUIVO> 62 4257
11 CH24_2 CPP 32 <ARQUIVO> 71 834
12 sBSDISK1 C 32 <ARQUIVO> 73 911
13 sH24_25 C 32 <ARQUIVO> 75 594
14 sBSDISK C 32 <ARQUIVO> 77 840
Pressione 'M': Para ver a lista de mais arquivos
Pressione 'R': Para recuperar um arquivo da lista acima R
|
CILINDRO DE EXIBIÇÃO: 0, CABEÇA: 1, SETOR: 2
FNO NOME EXT ATRIBUTO INÍCIO TAMANHO
----------------------------------------------------------------------------
0 WE 32 <ARQUIVO> 15 1800
1 s2_INFO C 32 <ARQUIVO> 5 4700
2 THELP CFG 32 <ARQUIVO> 2 22
3 THELP COM 32 <ARQUIVO> 3 11072
4 TIMEIT CPP 32 <ARQUIVO> 39 1186
5 TOUCH COM 32 <ARQUIVO> 42 5124
6 TRY1 CPP 32 <ARQUIVO> 53 1581
7 TURBOC CFG 32 <ARQUIVO> 57 30
8 AA CPP 32 <ARQUIVO> 58 260
9 ABC CPP 32 <ARQUIVO> 59 1036
10 ASSIGN1 CPP 32 <ARQUIVO> 62 4257
11 CH24_2 CPP 32 <ARQUIVO> 71 834
12 sBSDISK1 C 32 <ARQUIVO> 73 911
13 sH24_25 C 32 <ARQUIVO> 75 594
14 sBSDISK C 32 <ARQUIVO> 77 840
Insira o FNO do arquivo que deseja recuperar 1
Você deseja recuperar _2_INFO .C
Cilindro = 1, Cabeça = 0, Setor = 1 Integrando...
Insira o caminho e o nome do arquivo para recuperar o arquivo: c:\windows\desktop\H2_INFO.C
Recuperação concluída!!!
|
Comentários sobre codificação:
A função Display_Information é para ler as informações do arquivo e do diretório e do diretório raiz. Na Estrutura, estamos lendo as informações de 32 bytes para cada arquivo ou diretório com root[32].
Os arrays de inteiros não assinados name[8] e ext[3] são para nome de arquivo ou diretório para DOS no formato 8.3 (oito pontos três). Similarmente, um byte é para atributo e dois bytes para cluster inicial. long unsigned int size; é para armazenar o tamanho do arquivo de quatro bytes.
A função _bios_disk lê o setor, especificado pela estrutura finfo, e o status da operação é armazenado no resultado.
A partir de cada informação de 512 bytes lida pela função _bios_disk , até o final da área do diretório raiz , coletamos as informações dos arquivos e diretórios armazenados no disco e os exibimos na tela.
O inteiro file_no armazena o número do arquivo ou diretório na lista, começando em 0. Geralmente, o tamanho do diretório raiz é de 14 setores e o diretório raiz geralmente começa em Cilindro = 0, Cabeça = 0 e Setor = 2 no caso de 1,44 MB e disquete de 3½.
Se o usuário der o caractere 'M' ou 'm' como entrada, a informação do próximo setor é exibida se a escolha do usuário for 'R' ou 'r' as funções de recuperação são chamadas. A codificação da função recover() foi dada abaixo:
/* Função para iniciar a recuperação do arquivo especificado */
void recuperar(unsigned int *root,unsigned int len)
{
void clear_the_line(unsigned int r); /* Função para limpar uma linha na tela */
/* Função para integrar o arquivo especificado */
void integrar(longo int não assinado, int não assinado,
int sem sinal, int sem sinal);
int não assinado file_no,i;
char ch;
int não assinado *loc;
unsigned int cilindro,cabeça,setor;
int sem sinal start;
tamanho int longo sem sinal;
clear_the_line(21); /* Limpar o número da linha 21 */
clear_the_line(22); /* Limpar o número da linha 22 */
clear_the_line(23); /* Limpar o número da linha 23 */
clear_the_line(24); /* Limpar o número da linha 24 */
gotoxi(10,21);
cprintf("Digite o FNO. do arquivo que você deseja recuperar");
scanf("%u",&file_no); /* Obter o número do arquivo para ser
Recuperado */
loc=(raiz+(len*nº_arquivo/2));
/* Confirme o nome do arquivo a ser recuperado */
gotoxi(10,22);
cprintf("Você quer recuperar");
para(i=0;i<8;i++)
{
gotoxi(30+i,22);
cprintf("%c",*(loc+i)); /* Nome do arquivo */
}
gotoxi(38,22);
cprintf(".");
para(i=0;i<3;i++)
{
gotoxi(39+i,22);
cprintf("%c",*(loc+8+i)); /* Extensão de arquivo */
}
início=*(loc+12);
/// Desculpe, você selecionou um diretório \\\
se(*(loc+11)==16)
{
gotoxi(5,23);
cprintf("É um diretório. Você quer ver o
conteúdo deste diretório S/N");
ch=getch();
se(ch==27)
principal();
se(ch=='y' || ch=='Y')
{
/* Calcular Geometria */
calcular(início,&cilindro,&cabeça,&setor);
/* Exibir conteúdo do diretório */
Display_Information (cilindro, cabeçote, setor);
}
outro
/* Solicitar um arquivo novamente e continuar a recuperação */
recuperar(raiz,len);
}
outro
{
tamanho=*(loc+13);
/* Calcular para informações CHS */
calcular(início,&cilindro,&cabeça,&setor);
/* Integrar o arquivo */
integrar(tamanho,cilindro,cabeça,setor);
}
}
Comentários sobre codificação:
A função recover() é para obter a entrada do usuário para iniciar a recuperação. O número do arquivo fornecido como entrada pelo usuário para recuperar o arquivo é armazenado em file_no.
Se o número inserido for para a entrada do diretório, Display_Information() mostrará o conteúdo desse diretório, caso contrário, o nome do arquivo e a extensão do arquivo número file_no serão exibidos na tela para confirmar o arquivo a ser recuperado.
Para recuperar o arquivo especificado , as funções calculate() e integrate() são chamadas dentro da função. A codificação da função calculate() foi dada abaixo:
/* Função para calcular a geomatria CHS para a recuperação */
void calcular(inteiro sem sinal início,inteiro sem sinal *cilindro,
unsigned int *cabeçalho, unsigned int *setor)
{
int temp sem sinal;
*cilindro=0;
*cabeça=1;
*setor=14;
se(início<5)
*setor=14+início;
outro
{
temp= (início-4)/18;
se(temp>0)
{
se(temp%2==0)
*cabeça=0;
outro
*cabeça=1;
*cilindro+=1+temp/2;
}
outro
{
*cabeça=0;
*cilindro=1;
}
*setor=(início-4)%18;
}
/// Exibir o CHS do arquivo a ser recuperado \\\
gotoxi(10,23);
cprintf("Cilindro = %u, Cabeça = %u, Setor = %u",
*cilindro,*cabeça,*setor);
}
Comentários sobre codificação:
A função calculate() é para calcular as informações de Cilindro, Cabeça e Setor para o arquivo a ser recuperado. Após o cálculo, os números de Cilindro, Cabeça e Setor são exibidos na tela.
A codificação para a função integrate() foi fornecida abaixo:
/* Integrar arquivo e salvar o arquivo recuperado no caminho e nome de arquivo especificados */
void integrar(longo unsigned int tamanho,
cilindro int sem sinal,
cabeça int não assinada,
setor int não assinado)
{
void limpar_a_linha(int não assinado);
/* Função para verificar se há erros no setor */
int verificar_o_setor(int não assinado, int não assinado,
int sem sinal);
estado interno;
char buf[512],*Nome_do_arquivo_com_caminho;
estrutura diskinfo_t dinfo;
resultado int sem sinal;
ARQUIVO *fp;
int sem sinal esquerda,i;
int sec sem sinal;
/* Digite o caminho de destino e o nome do arquivo para salvar o arquivo recuperado */
gotoxi(2,24);
cprintf("Digite o caminho e o nome do arquivo para recuperar o arquivo: ");
fflush(padrão);
obtém(Nome_do_arquivo_com_caminho);
fp=fopen(Nome_do_arquivo_com_caminho,"wb");
/* Se ocorrer um erro, exibir mensagem de erro e obter o caminho de entrada e o nome do arquivo novamente */
se(fp==NULO)
{
gotoxi(5,25);
cprintf("Erro ao abrir o arquivo");
obter();
limpar_a_linha(24);
gotoxi(0,25);
cprintf(" ");
integrar(tamanho,cilindro,cabeça,setor); /* Insira o
Destino Novamente */
}
/* Se tudo estiver bem, integre e escreva */
gotoxi(50,23);
cprintf("Integrando........");
esquerda= tamanho%512;
seg = tamanho/512;
seg++;
enquanto(seg>0)
{
dinfo.drive = 0x00; /* número da unidade para A: */
dinfo.head = head; /* número da cabeça do disco */
dinfo.track = cylinder; /* número da trilha */
dinfo.sector= setor; /* número do setor */
dinfo.nsectors=1; /* contagem de setores */
dinfo.buffer = buf; /* buffer de dados */
resultado = _bios_disk(_DISK_READ, &dinfo);
/* Se houver erro durante a leitura de qualquer setor */
se((resultado & 0xff00) != 0)
{
gotoxi(5,25);
cprintf("erro de leitura Cilindro %u, Cabeça %u, Setor %u",
cilindro, cabeça, setor);
}
outro
{
se(seg==1)
{
para(i=0;i<esquerda;i++)
fputc(buf[i],fp); /* Escrever o Integrado
Informações para o arquivo */
}
outro
{
fwrite(buf,512,1,fp);
}
Comentários sobre codificação:
A função integrate() é o módulo real que realiza a recuperação do arquivo especificado pelo usuário, neste programa de recuperação .
O nome do arquivo com o caminho de destino para armazenar o arquivo recuperado é armazenado no ponteiro de caractere *Filename_with_path. Se houver algum erro ao abrir o arquivo de destino, uma mensagem de erro será exibida e o usuário será solicitado novamente a digitar o destino.
A função _bios_disk(_DISK_READ, &dinfo); lê os dados do arquivo da área de dados do disco setor por setor, especificado pela estrutura dinfo e armazenado no buffer de dados buf. Esses dados de 512 bytes são gravados no arquivo de destino. Isso é repetido até que o arquivo completo seja integrado.
A função status=verify_the_sector (cylinder,head,sector); verifica o setor a ser lido. Se o status = 10, representa um setor ruim (0xA). A codificação da função foi dada abaixo:
/// Verifique o setor. (Nenhum dado é transferido aqui) \\\
int verificar_o_setor(int sem sinal c,int sem sinal h,int sem sinal s)
{
estado interno;
char *buf;
união REGS dentro, fora;
estrutura SREGS sg;
in.h.ah = 0x04; /* Número da função */
in.h.al = 1; /* Número de setores a serem verificados*/
em.h.dl = 0x00; /* Número do disco para A: */
pol.h.ch = c; /* Número do cilindro */
pol.h.dh = h; /* Número do cabeçalho */
em.h.cl = s; /* Número do setor */
in.x.bx = FP_OFF(buf);/* Deslocamento */
sg.es = FP_SEG(buf); /* Segmento */
int86x(0x13,&entrada,&saída,&sg); /* Chamar função 4H
a partir de INT 13H */
se(fora.x.cflag)
{
status=fora.h.ah;
}
retornar(estado);
}
Comentários de codificação:
A função verify_the_sector() verifica o setor que será lido pela função _bios_disk() e retorna o status da operação. A função usa INT 13H e a função 4H para verificar o setor.
*buf — buffer de dados, 0x04 — número da função especificada por in.h.ah = 0x04; e in.h.al = 1; indica que um setor deve ser verificado por vez. em.h.dl = 0x00; usado para unidade de disquete número A:, c, h e s são números de cilindro, cabeça e setor .
A função int86x() é usada para chamar INT 13H (função 4H) com valores de registradores de segmento . O status da operação é retornado como um status inteiro.
A função clear_the_line() limpa a linha especificada na tela. A codificação da função é a seguinte:
/* Função para limpar uma linha na tela para o número de linha especificado */
void clear_the_line(string inteira sem sinal)
{
coluna inteira sem sinal;
/* Existem 80 colunas em uma linha */
para(coluna=1;coluna<=80;coluna++)
{
gotoxy(coluna,linha);
cprintf(" "); /* Limpar com " " */
}
}
Comentários de codificação:
A função é usada para limpar a linha especificada na tela . A função é chamada com o número da linha que precisa ser apagada da tela.