Entorno MacOS: sistema operativo de escritura a mano: implementación de comandos de 43 dir y escritura de archivos

comando dir y escritura de archivos

1. Introducción

El comando de consola que se implementará en esta sección es dir

Su función es enumerar la información del archivo en el directorio actual.

Nuestro sistema operativo actual no tiene disco duro ni ningún sistema de archivos.

Entonces, ¿de dónde provienen los archivos enumerados por este comando?

Dado que el núcleo de nuestro sistema está almacenado en un disquete, consideramos directamente el disquete como el disco duro del sistema.

Este comando enumera los archivos almacenados en el disquete virtual.

Supongamos que almacenamos dos archivos en un disquete virtual.

Son abc.exe y efg.sys respectivamente. Los tamaños de archivo son 256 bytes y 128 bytes respectivamente.

2.Código

Primero veamos cómo el sistema de archivos FAT12 registra la información del archivo.

Cada archivo almacenado en un sistema FAT12 tiene un directorio de archivos para almacenar información básica sobre el archivo.

La estructura de datos de este directorio es la siguiente

struct FILEINFO {
    unsigned char name[8], ext[3], type;
    char  reserve[10];
    unsigned short time, date, clustno;
    unsigned int  size;
};

Los primeros 8 bytes de esta estructura corresponden al nombre, que es el nombre del archivo, es decir, el nombre del archivo almacenado no debe exceder los 8 caracteres.

Los siguientes tres bytes corresponden al duodécimo byte de la extensión del archivo, que es tipo, que corresponde al tipo de archivo.

Su valor significa lo siguiente

0x01 只读文件
0x02 隐藏文件
0x04 系统文件
0x08 非文件信息
0x10 目录

Los siguientes 10 bytes están reservados, según lo especificado por Microsoft.

Los siguientes dos bytes

Primero, la hora y la fecha se utilizan para representar la hora de generación del archivo.

Los últimos 4 bytes son el tamaño del archivo.

La información actualmente almacenada en nuestro disquete virtual.

El diseño es así: los primeros 512 bytes son el código del sector de arranque.

Lo siguiente que se almacena es el kernel del sistema.

Luego está el directorio de archivos correspondiente al sistema de archivos FAT12.

Es decir, si la estructura de datos descrita anteriormente almacena varios archivos, habrá varias estructuras de datos FILEINFO.

A partir de esto, primero echemos un vistazo a qué tan grande es nuestro kernel actual para que podamos calcular la ubicación del directorio de archivos en el disquete.

Luego determine la ubicación correspondiente después de cargarla en la memoria.

Ejecute el proyecto java que genera el disquete virtual y pase la salida

El tamaño actual del kernel del sistema es de 71 sectores en total.

El tamaño de cada sector es de 512 bytes.

Entonces el tamaño total del kernel es 71*512=0x8E00 bytes

Cuando nuestro kernel se carga en la memoria, comienza desde la dirección inicial 0x8000

Entonces la dirección final del kernel en la memoria es

0x10E00 = 0x8000 + 0x8E00

Dado que colocamos la información del directorio de archivos directamente al final del kernel, la dirección inicial de la información del directorio de archivos es 0x10E00.

A continuación, veamos cómo se escribe la información del directorio de archivos en el disco virtual.

import java.nio.ByteBuffer;


public class FileHeader {
    
    
    private byte[] header = new byte[32];

    public void setFileName(String s) {
    
    
        int len = s.length() > 8 ? 8 : s.length();
        for (int i = 0; i < len; i++) {
    
    
            header[i] = (byte)s.charAt(i);
        }
    }

    public void setFileExt(String s) {
    
    
        int len = s.length() > 3 ? 3 : s.length();
        for (int i = 0; i < len; i++) {
    
    
            header[8+i] = (byte)s.charAt(i);
        }
    }

    public void setFileType(Byte t) {
    
    
        header[11] = t;
    }

    public void setFileTime(byte[] time) {
    
    
        header[22] = time[0];
        header[23] = time[1];
    }

    public void setFileDate(byte[] date) {
    
    
        header[24] = date[0];
        header[25] = date[1];
    }

    public void setFileClusterNo(byte[] no) {
    
    
        header[26] = no[0];
        header[27] = no[1];
    }

    public void setFileSize(int size) {
    
    
        byte[] buf = ByteBuffer.allocate(4).putInt(size).array();
        for (int i = 0; i < 4; i++) {
    
    
            header[28+i] = buf[3 - i];
        }
    }

    public byte[] getHeaderBuffer() {
    
    
        return header;
    }
}

Una clase FileHeader se utiliza para representar un directorio de archivos y corresponde a la estructura de datos FILEINFO mencionada anteriormente.

Proporciona varias interfaces para configurar extensiones de nombres de archivos y otra información relacionada.


public class DiskFileSystem {
    
    
    private Floppy floppyWriter;
    private int beginSec;
    private int fileHeaderCount = 0;
    private byte[] buffer = new byte[512];
    private int cylinder = 0;

    public DiskFileSystem(Floppy disk, int  cylinder, int sec) {
    
    
        this.floppyWriter = disk;
        this.beginSec = sec;
        this.cylinder = cylinder;
    }

    public void addHeader(FileHeader header) {
    
    
        if (fileHeaderCount >= 16) {
    
    
            flashFileHeaders();
            fileHeaderCount = 0;
            buffer = new byte[512];
            beginSec++;
        }

        byte[] headerBuf = header.getHeaderBuffer();
        for (int i = 0; i < 32; i++) {
    
    
            buffer[fileHeaderCount * 32 + i] = headerBuf[i];
        }

        fileHeaderCount++;
    }

    public void flashFileHeaders() {
    
    
        floppyWriter.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0 , cylinder, beginSec, buffer);
    }
}

DiskFileSystem se utiliza para escribir la estructura del directorio de archivos en una ubicación específica en el disco.

La función inicial de esta clase necesita pasar varios parámetros.

El disco representa un disco virtual.

cilindro representa el cilindro en el que se escribirá el directorio de archivos.

sec representa el sector inicial del cilindro

Compilemos y ejecutemos

Uso del disquete después de ejecutar Java

......
Load file kernel.bat to floppy with cylinder: 3 and sector:7
Load file kernel.bat to floppy with cylinder: 3 and sector:8
Load file kernel.bat to floppy with cylinder: 3 and sector:9
Load file kernel.bat to floppy with cylinder: 3 and sector:10
Load file kernel.bat to floppy with cylinder: 3 and sector:11
Load file kernel.bat to floppy with cylinder: 3 and sector:12
Load file kernel.bat to floppy with cylinder: 3 and sector:13
Load file kernel.bat to floppy with cylinder: 3 and sector:14
Load file kernel.bat to floppy with cylinder: 3 and sector:15
Load file kernel.bat to floppy with cylinder: 3 and sector:16
Load file kernel.bat to floppy with cylinder: 3 and sector:17
Load file kernel.bat to floppy with cylinder: 3 and sector:18
Load file kernel.bat to floppy with cylinder: 4 and sector:1
Load file kernel.bat to floppy with cylinder: 4 and sector:2
Load file kernel.bat to floppy with cylinder: 4 and sector:3
Load file kernel.bat to floppy with cylinder: 4 and sector:4
Load file kernel.bat to floppy with cylinder: 4 and sector:5
Load file kernel.bat to floppy with cylinder: 4 and sector:6
Load file kernel.bat to floppy with cylinder: 4 and sector:7
Load file kernel.bat to floppy with cylinder: 4 and sector:8
Load file kernel.bat to floppy with cylinder: 4 and sector:9
Load file kernel.bat to floppy with cylinder: 4 and sector:10

Puede ver que el kernel finalmente escribió en el cuarto cilindro y el sector 17 del disquete virtual.

(El maestro original tiene 17 años y yo 10, pero soy más joven que él, así que solo sigo el consejo del maestro. Por supuesto, tú también puedes seguir tu propia situación)

Dado que nuestro directorio de archivos sigue el almacenamiento del kernel

Por lo tanto, nuestro directorio de archivos debe escribirse en el sector 18 del cuarto cilindro.

Entonces, cuando generamos un disquete virtual

Escriba el directorio de archivos en la ubicación especificada

 public void makeFllopy()   {
        writeFileToFloppy("kernel.bat", false, 1, 1);

        //test file system
			  // 这里设置文件的存储位置
        DiskFileSystem fileSys = new DiskFileSystem(floppyDisk, 4, 18);
        FileHeader header = new FileHeader();
        header.setFileName("abc");
        header.setFileExt("exe");
        byte[] date = new byte[2];
        date[0] = 0x11;
        date[1] = 0x12;
        header.setFileTime(date);
        header.setFileDate(date);
        header.setFileSize(256);
        fileSys.addHeader(header);

        header = new FileHeader();
        header.setFileName("efg");
        header.setFileExt("sys");
        header.setFileSize(128);
        fileSys.addHeader(header);

        fileSys.flashFileHeaders();

        //test file system

        floppyDisk.makeFloppy("system.img");
    }

El código anterior primero crea dos directorios de archivos, cuyos dos nombres de archivo son abc.exe y efg.sys.

Estos dos archivos son virtuales, solo construimos sus directorios en el disco.

No hay datos reales para estos dos archivos en el disco.

Una vez que tengamos el directorio de archivos en el disco, debemos escribir el código del kernel para que el kernel pueda leer y mostrar información relevante.

Ajustar el código

Primero agregue el siguiente código en global_define.h

#define  ADR_DISKIMG  0x10E00

struct FILEINFO {
    unsigned char name[8], ext[3], type;
    char  reserve[10];
    unsigned short time, date, clustno;
    unsigned int  size;
};

ADR_DISKIMG es la dirección inicial del directorio de archivos en la memoria

FILEINFO corresponde a la información del directorio de archivos correspondiente al sistema de archivos FAT12 mencionado anteriormente.

Cuando ingresamos el directorio de comando en la consola, la consola lee los datos de la estructura FILEINFO desde la ubicación especificada.

Y muestre el nombre del archivo correspondiente y el tamaño del archivo.

El código es el siguiente en write_vga_desktop.c

void console_task(struct SHEET *sheet, int memtotal) {
....
struct FILEINFO* finfo = (struct FILEINFO*)(ADR_DISKIMG);

    for(;;) {
    ....
    else if (strcmp(cmdline, "dir") == 1) {
          while (finfo->name[0] != 0) {
            char s[13];
            s[12] = 0;
            int k;
            for (k = 0; k < 8; k++) {
              if (finfo->name[k] != 0) {
              	s[k] = finfo->name[k]; 
              }else {
              	break;
            	}
            }

            int t = 0;
            s[k] = '.';
            k++;
            for (t = 0; t < 3; t++) {
            	s[k] = finfo->ext[t];
            	k++;
            }

            showString(shtctl, sheet, 16, cursor_y, COL8_FFFFFF, s);
            int offset = 16 + 8*15;
            char* p = intToHexStr(finfo->size);
            showString(shtctl, sheet, offset, cursor_y, COL8_FFFFFF, p);
            cursor_y = cons_newline(cursor_y, sheet);
            finfo++;

          }
    ....
    }
....
}

Cuando la consola recibe el comando dir

Primero lee la información del primer directorio de archivos a partir de la dirección ADR_DISKIMG

Si el primer carácter del nombre del archivo no es 0

Luego indica que los siguientes 32 bytes representan información válida del directorio de archivos.

Entonces, el código primero obtiene el nombre del archivo, luego la extensión del archivo y finalmente el tamaño del archivo.

Luego muestre esta información a la consola en secuencia

Luego vaya más allá de los 32 bytes y luego determine si los siguientes 32 bytes representan información válida del directorio de archivos.

Si continúa mostrando información relevante de acuerdo con la lógica original

3. Compile y ejecute

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/w776341482/article/details/128662406
Recomendado
Clasificación