MacOS环境-手写操作系统-43-dir命令的实现 和 文件写入

简介: MacOS环境-手写操作系统-43-dir命令的实现 和 文件写入

dir命令 和 文件写入

1.简介

本节要实现的控制台命令是dir


它的作用是列举出当前目录下的文件信息


我们当前的操作系统根本没有硬盘 更没有文件系统


那么这个命令列举的文件从哪里来呢?


由于我们的系统内核是存储在软盘上的 因此 我们直接把软盘当做系统硬盘


该命令列举的是存储在虚拟软盘上的文件


假设我们在虚拟软盘上存储了两个文件


分别为abc.exe, efg.sys,文件的大小分别为256字节和128字节


2.代码

我们先看看FAT12文件系统是如何记录文件信息的


每个存储在FAT12系统上的文件都有一个文件目录 用于存储文件的基本信息


这个目录的数据结构如下


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


这个结构体的头8个字节对应name,也就是文件名 也就是说存储的文件 它的名称绝不能对于8个字符


接下来三个字节对应的是文件扩展名 第12个字节 也就是type 它对应的是文件的类型


它的值意义如下


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


接下来的10字节为保留 这是微软规定的


跟着的两个字节


首先是time 和 date 用于表示文件的生成时间


最后4个字节就是文件的大小


当前 我们的虚拟软盘所存储的信息


其布局是这样的 最开始的512字节是引导扇区代码


接下来存储的就是系统内核


然后跟着是FAT12文件系统对应的文件目录


也就是上面描述的数据结构 存了几个文件 就有几个FILEINFO数据结构


由此先看看 我们当前的内核到底有多大 这样我们才能计算出文件目录在软盘中的位置


进而确定它加载到内存后 所对应的位置


运行生成虚拟软盘的java工程 通过输出


当前系统内核的大小总共是71个扇区


每个扇区大小是512字节


因此内核的总大小是71*512=0x8E00 字节


我们的内核加载到内存时 是从起始地址0x8000开始的


于是内核在内存中的末尾地址就是


0x10E00 = 0x8000 + 0x8E00


由于我们把文件的目录信息直接跟在内核末尾的,因此文件目录信息的起始地址就是0x10E00.


接着我们看看 文件目录信息是如何写到虚拟磁盘上的

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

一个FileHeader 类用来表示一个文件目录 它对应前头提到的FILEINFO数据结构

它提供了几个接口 用来设置文件名 扩展名等相关信息


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 用于把文件目录结构写入到磁盘的指定地方


该类的初始函数需要传入几个参数


disk 表示虚拟磁盘


cylinder 表示文件目录所要写入的柱面


sec 表示所在柱面的起始扇区


我们编译运行一下


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


可以看到 内核最后写入到虚拟软盘的第4柱面,第17扇区


(原老师是17 我是10 但是我比他小 所以我按老师的来就行 当然 也可以根据自己的情况来)


由于我们的文件目录紧跟着内核存储


因此 我们的文件目录要写入到第4柱面 第18扇区


于是我们在生成虚拟软盘时


在指定位置写下文件目录

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

上面代码先创建了两个文件目录 这两个文件名分别为abc.exe 和 efg.sys


这两个文件是虚拟的 我们只在磁盘上构造它们的目录


在磁盘上并没有这两个文件的实际数据


磁盘上有了文件目录后 我们要编写内核代码 让内核能够读取显示相关信息


调整下代码


首先在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 就是文件目录在内存中的起始地址


FILEINFO对应的就是前面提到过的FAT12文件系统对应的文件目录信息


当我们在控制台输入命令dir 后 控制台从指定位置 把FILEINFO结构数据读取出来


并把对应的文件名和文件大小显示出来


代码如下 在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++;

          }
    ....
    }
....
}

当控制台收到dir命令时


它先从地址ADR_DISKIMG开始 读取第一个文件目录信息


如果文件名的起始第一个字符不是0


那么表明接下来的32字节表示有效的文件目录信息


于是代码先获取文件名 然后获取文件扩展名 最后得到文件大小


然后依次把这些信息显示到控制台上


接着越过32字节 再判断接下来的32个字节是否表示有效的文件目录信息


如果是 再按照原有逻辑 继续显示相关信息


3.编译和运行

目录
相关文章
|
28天前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
36 3
|
1月前
|
Linux 编译器 C语言
./build.sh:行1: g++: 未找到命令的错误问题在centos操作系统下面如何解决
通过上述步骤,您应该能够有效地解决CentOS系统中 `g++: 未找到命令`的错误。确保软件开发环境配置得当,对于顺利执行编译脚本和日常开发工作至关重要。如果问题依然存在,考虑检查脚本内的命令路径引用是否正确,或进一步排查系统配置问题。
104 0
|
1月前
|
存储 C语言 iOS开发
MacOS环境-手写操作系统-48-让内核从错误中恢复
MacOS环境-手写操作系统-48-让内核从错误中恢复
35 0
|
1月前
|
存储 API C语言
MacOS环境-手写操作系统-46,47-C语言开发应用程序
MacOS环境-手写操作系统-46,47-C语言开发应用程序
35 0
|
1月前
|
编译器 API C语言
MacOS环境-手写操作系统-45-C语言开发应用程序
MacOS环境-手写操作系统-45-C语言开发应用程序
44 0
|
1月前
|
小程序 iOS开发 MacOS
MacOS环境-手写操作系统-44-运行简单的程序
MacOS环境-手写操作系统-44-运行简单的程序
22 0
|
14天前
|
安全 Linux 数据安全/隐私保护
Vanilla OS:下一代安全 Linux 发行版
【10月更文挑战第30天】
37 0
Vanilla OS:下一代安全 Linux 发行版
|
17天前
|
人工智能 安全 Linux
|
1月前
|
Unix 物联网 大数据
操作系统的演化与比较:从Unix到Linux
本文将探讨操作系统的历史发展,重点关注Unix和Linux两个主要的操作系统分支。通过分析它们的起源、设计哲学、技术特点以及在现代计算中的影响,我们可以更好地理解操作系统在计算机科学中的核心地位及其未来发展趋势。
|
3月前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
109 3