概况

FAT32真的有点繁杂 道理不是很难 细节特别多 写了代码才发现要写吐了
unicode跟ascii的转化 簇和扇区的边界 就这两点真的麻烦

完成功能:

1、文件列表
2、文件删除
3、文件重命名(不管长短,只能重命名为短的,长的没调好,有bug)
4、文件复制(不管长短,复制为短的,长的没调好,有bug)

很好的参考资料:

FAT32学习-1、BPB
FAT32学习-2、FAT表
FAT32学习-3、数据区

编译环境:

vs 2019 x86

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<queue>
#include<iostream>
#include<stack>
#include<vector>
#include<bitset>
#include<set>
#include<map>
#include<windows.h>
#include<wchar.h>
#include<locale.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define clr(a,x) memset(a,x,sizeof(a))
#define inf (0x7fffffff)
typedef long long ll;
using namespace std;

// buffer_size应当和扇区大小一样
#define buffer_size (512)
// 全局变量
int sector_per_cluster;
int offset_FAT;
int offset_FAT_2;
int offset_data;
HANDLE hDisk;
DISK_GEOMETRY info_disk;
unsigned char buffer[buffer_size];
unsigned char buffer_cluster[buffer_size*16]; // 这个的大小与磁盘簇大小相关
int bytes_read;
int bytes_return;
int bytes_write;
int cnt_per_FAT;
int root_first_cluster;
int FAT_buffer[16384*buffer_size/4]; // 这个的大小与磁盘大小相关

// 按照一个字节两个十六进制数的格式输出缓冲区的内容 
void printf_buffer(unsigned char* buffer, int bytes_read) {
    puts("读取扇区内容:");
    int cnt = 0;
    for (int i = 0; i < bytes_read; i++) {
        cnt++;
        int tmp1 = buffer[i] % 16;
        int tmp2 = buffer[i] / 16;
        printf("%x%x ", tmp2, tmp1);
        if (cnt % 8 == 0 && cnt != 32) {
            putchar(' ');
        }
        else if (cnt == 32) {
            putchar('\n');
            cnt = 0;
        }
    }
}
// 根据0x0B处的值是不是0F来判断长短文件名或者为空
int get_type(unsigned char* buffer) {
    if (buffer[0] == 0xE5) return 3;// 被删除
    if (buffer[0] == 0x00) return 0;// 空
    if (buffer[0x0B] == 0x0F) return 1;// 长文件名
    return 2;// 短文件名
}
// 读取长文件名的32个字节 如果是第一块则返回1
bool read_long_name(unsigned char* buffer,wchar_t*name) {
    int cnt = 0;
    for (int i = 0x01; i < 0x01 + 10; i += 2) {
        name[cnt++] = buffer[i] + 256 * buffer[i + 1];
    }
    for (int i = 0x0E; i < 0x0E + 12; i += 2) {
        name[cnt++] = buffer[i] + 256 * buffer[i + 1];
    }
    for (int i = 0x1C; i < 0x1C + 4; i += 2) {
        name[cnt++] = buffer[i] + 256 * buffer[i + 1];
    }
    //wcout << name << endl;
    return buffer[0x00] % 32 == 1;
}
// 读取短文件名的32个字节
struct file_info {
    char name[15];// 文件名
    char ext[5];// 后缀名
    int create_hour, create_minute,create_second;
    int create_year, create_month, create_day;// 创建信息
    int size;// 大小
    int first_cluster;// 起始簇号
    file_info() {
        memset(ext, 0, sizeof(ext));
        create_hour = create_minute = create_second = 0;
        create_year = create_month = create_day = 0;
        size = first_cluster = 0;
    }
    // 当该项目没有对应长文件名时用于输出文件名
    void print_name() {
        printf("%s   ", name);
    }
    // 输出文件详细信息
    void print_info() {
        printf("后缀名:%s", ext);
        printf("  创建于:%d/%d/%d", create_year, create_month, create_day);
        if(create_hour < 10)
            printf(" 0%d:", create_hour);
        else
            printf(" %d:", create_hour);
        if (create_minute < 10)
            printf("0%d:", create_minute);
        else
            printf("%d:", create_minute);
        if (create_second < 10)
            printf("0%d", create_second);
        else
            printf("%d", create_second);
        printf("  大小:%d bytes", size >> 8);
        printf("  起始文件簇:%d\n", first_cluster);
    }
};
// 返回短文件名段中文件信息的结构体 根据格式提取信息
file_info read_short_name(unsigned char* buffer) {
    file_info info;
    int i = 0;
    for (i = 0x00; i <= 0x07; i++) {
        if (buffer[i] != 0x20)
            info.name[i] = buffer[i];
        else {
            break;
        }
    }
    info.name[i++] = '.';
    info.name[i++] = buffer[0x08];
    info.name[i++] = buffer[0x09];
    info.name[i++] = buffer[0x0A];
    info.name[i++] = '\0';
    for (int i = 0x08; i <= 0x0A; i++)
        info.ext[i - 0x08] = buffer[i];
    info.ext[3] = '\0';
    int tmp = buffer[0x0E] + buffer[0x0F] * 256;
    info.create_hour = tmp >> 11;
    info.create_minute = (tmp >> 5) % (1 << 6);
    info.create_second = (tmp % (1 << 5))*2 + (int)floor(buffer[0x0D]*0.01);
    tmp = buffer[0x10] + buffer[0x11] * 256;
    info.create_year = (tmp >> 9) + 1980;
    info.create_month = (tmp >> 5) % (1 << 4);
    info.create_day = tmp % (1 << 5);
    for (int i = 0x1F; i >= 0x1c; i --)
        info.size = (info.size + buffer[i]) << 8;
    info.first_cluster = buffer[0x1A] + buffer[0x1B] * 256;
    return info;
}
// 查找对应文件名是否存在 存在的话返回扇区与偏移 长文件名返回第一块
bool search_file_name(wchar_t*wname,char*sname,int& num_cluster,int& sector_on,int& pos_on) {
    wchar_t file_wname[257];
    file_wname[256] = '\0';
    int cnt_wname = 256 - 13;
    bool get_long_name = 0;
    int type = -1;
    int bytes_read;

    num_cluster = root_first_cluster;
    for (int cnt_sector = 0; type != 0; cnt_sector++) {
        // 根目录跨越多个文件簇的情况
        if (cnt_sector == sector_per_cluster) {
            cnt_sector = 0;
            if (FAT_buffer[num_cluster] == 0x0FFFFFFF) {
                break;
            }
            num_cluster = FAT_buffer[num_cluster];
        }
        //cout << "now sector == " << cnt_sector << endl;
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + ((num_cluster - 2) * sector_per_cluster + cnt_sector) * info_disk.BytesPerSector,// 低位偏移量  
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        ReadFile(hDisk,                         // 文件句柄 
            buffer,                             // 读入缓冲区 
            info_disk.BytesPerSector,           // 读入字节数 
            (LPDWORD)&bytes_read,               // 实际读取字节数指针 
            NULL);                              // overlap属性 
        //printf_buffer(buffer, bytes_read);
        for (int pos = 0; pos < (int)info_disk.BytesPerSector; pos += 32) {
            type = get_type(buffer + pos);
            //cout << type << endl;
            // 存在长文件名
            if (type == 1) {
                get_long_name = 1;
                bool first = read_long_name(buffer + pos, file_wname + cnt_wname);
                //cout << first << endl;
                if (first == 1) {
                    // wcout << wname << ' ' << file_wname + cnt_wname << endl;
                    if (wcscmp(wname, file_wname + cnt_wname) == 0) {
                        sector_on = cnt_sector;
                        pos_on = pos;
                        return 1;
                    }
                    cnt_wname = 256 - 13;
                }
                else cnt_wname -= 13;
            }
            else if (type == 2) {
                file_info info = read_short_name(buffer + pos);
                if (get_long_name == 0) {// 之前没有读到长文件名 
                    if (strcmp(sname, info.name) == 0) {
                        sector_on = cnt_sector;
                        pos_on = pos;
                        return 1;
                    }
                }
                else get_long_name = 0;
                //cout << file_sname << endl;
            }
            else if (type == 3) continue;
            else break;
        }
    }
    return 0;
}
// 删除文件目录 第一位赋值为e5即可 不存在返回0 将位置修正为短文件名的
bool delete_file_name(wchar_t* wname, char* sname, int& num_cluster, int&sector_on, int&pos_on) {
    bool exist_file = search_file_name(wname, sname, num_cluster, sector_on, pos_on);
    if (exist_file == 0) {
        return 0;
    }
    puts("正在删除文件名目录项...");
    // 判断找到的是长文件名还是短文件名
    bool type = 0;
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_data + sector_on * info_disk.BytesPerSector,// 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        buffer,                             // 读入缓冲区 
        info_disk.BytesPerSector,           // 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性 
    if (buffer[pos_on + 0x0B] == 0x0F) {
        type = 1;
    }
    // 短文件名
    if (type == 0) {
        // 直接写回去
        bytes_write = buffer_size;
        buffer[pos_on] = 0xE5;
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + sector_on * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        WriteFile(
            hDisk,                          // 文件句柄
            buffer,                         // 数据缓存区指针
            bytes_write,                    // 写字节数
            (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
            NULL);                          // overlap属性
    }
    // 长文件名
    else {
        // 删除长文件名
        bool last = 0; // 是否删到长文件名最后一个
        for (int cnt_sector = sector_on; last == 0; cnt_sector --) {
            //cout << "now sector == " << cnt_sector << endl;
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_data + cnt_sector * info_disk.BytesPerSector,// 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                buffer,                             // 读入缓冲区 
                info_disk.BytesPerSector,           // 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性 
            for (int pos = (cnt_sector == sector_on)? pos_on : buffer_size - 32; pos >= 0; pos -= 32) {
                if( ( buffer[pos] & (1 << 6) ) == 0)
                    buffer[pos] = 0xE5;
                else {
                    last = 1;
                    buffer[pos] = 0xE5;
                    break;
                }
            }
            // 写回去
            bytes_write = buffer_size;
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_data + cnt_sector * info_disk.BytesPerSector,// 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            WriteFile(
                hDisk,                          // 文件句柄
                buffer,                         // 数据缓存区指针
                bytes_write,                    // 写字节数
                (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
                NULL);                          // overlap属性
        }
        // 将pos_on与sector_on设置为短文件名的
        if (pos_on == buffer_size - 32) {
            pos_on = 0;
            sector_on++;
        }
        else {
            pos_on += 32;
        }
        // 删除短文件名
        bytes_write = buffer_size;
        buffer[pos_on] = 0xE5;
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + sector_on * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置
        WriteFile(
            hDisk,                          // 文件句柄
            buffer,                         // 数据缓存区指针
            bytes_write,                    // 写字节数
            (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
            NULL);                          // overlap属性
    }
    return 1;
}
// 删除文件FAT内容
void delete_file_data (file_info info) {
    // 把FAT读出来读成int
    puts("正在删除对应FAT表项...");
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT,                         // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        FAT_buffer,                         // 读入缓冲区 
        cnt_per_FAT * info_disk.BytesPerSector,// 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性     
    // 清空对应FAT表项
    int now_cluster = info.first_cluster;
    // 空文件没有FAT表项
    // cout << now_cluster << endl;
    if (now_cluster == 0) {
        puts("删除完毕!");
        return;
    }
    while (FAT_buffer[now_cluster] != 0x0FFFFFFF) {
        // cout << now_cluster << endl;
        int tmp = FAT_buffer[now_cluster];
        FAT_buffer[now_cluster] = 0;
        now_cluster = tmp;
    }
    FAT_buffer[now_cluster] = 0;
    // 写回去
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT,                         // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    bytes_write = cnt_per_FAT * info_disk.BytesPerSector;
    WriteFile(
        hDisk,                          // 文件句柄
        FAT_buffer,                     // 数据缓存区指针
        bytes_write,                    // 写字节数
        (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
        NULL);                          // overlap属性 
    // 对于FAT表2也要一样的操作
    // 把FAT读出来读成int
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT_2,                       // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        FAT_buffer,                         // 读入缓冲区 
        cnt_per_FAT * info_disk.BytesPerSector,// 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性 
    // 清空对应FAT表项
    now_cluster = info.first_cluster;
    while (FAT_buffer[now_cluster] != 0x0FFFFFFF) {
        int tmp = FAT_buffer[now_cluster];
        FAT_buffer[now_cluster] = 0;
        now_cluster = tmp;
    }
    // 写回去
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT_2,                       // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    bytes_write = cnt_per_FAT * info_disk.BytesPerSector;
    WriteFile(
        hDisk,                          // 文件句柄
        FAT_buffer,                     // 数据缓存区指针
        bytes_write,                    // 写字节数
        (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
        NULL);                          // overlap属性 
    puts("删除完毕!");
}
// 获取目录最后一个位置
void get_last_index(int& num_cluster, int& sector_on, int& pos_on) {
    int type = -1;
    num_cluster = root_first_cluster;
    for (int cnt_sector = 0; type != 0; cnt_sector++) {
        // 根目录跨越多个文件簇的情况
        if (cnt_sector == sector_per_cluster) {
            cnt_sector = 0;
            if (FAT_buffer[num_cluster] == 0x0FFFFFFF) {
                break;
            }
            num_cluster = FAT_buffer[num_cluster];
        }
        //cout << "now sector == " << cnt_sector << endl;
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + ((num_cluster - 2) * sector_per_cluster + cnt_sector) * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        ReadFile(hDisk,                         // 文件句柄 
            buffer,                             // 读入缓冲区 
            info_disk.BytesPerSector,           // 读入字节数 
            (LPDWORD)&bytes_read,               // 实际读取字节数指针 
            NULL);                              // overlap属性
        for (int pos = 0; pos < (int)info_disk.BytesPerSector; pos += 32) {
            type = get_type(buffer + pos);
            if (type == 0) { // 空 即最后一项
                pos_on = pos;
                sector_on = cnt_sector;
                break;
            }
        }
    }
}
// 创建新的长文件名 可能有一点小bug 重新写入到硬盘中可能有点小问题
void create_long_name(wchar_t* wname, char* sname, unsigned char* file_data) {
    // 计算校验值
    unsigned char tmp_name[12];
    for (int i = 0x00; i <= 0x07; i++) {
        if (i < (int)strlen(sname))
            tmp_name[i] = sname[i];
        else
            tmp_name[i] = 0x20;
    }
    if (strlen(sname) > 8) {
        tmp_name[0x06] = '~';
        tmp_name[0x07] = (unsigned char)('0' + strlen(sname) - 8);
    }
    for (int i = 0x08; i <= 0x0B; i++) {
        tmp_name[i] = file_data[i];
    }

    unsigned char check_sum = 0;
    int j = 0;
    for (int i = 0x0B; i > 0; i--)
        check_sum = ((check_sum & 1) ? 0x80 : 0) + (check_sum >> 1) + tmp_name[j++];
    // printf("%x\n", check_sum);
    // 加上拓展名
    int len = wcslen(wname);
    size_t num_convert;
    wname[len] = L'.';
    mbstowcs_s(&num_convert, wname + len + 1, 8, (char*)(file_data + 0x08), 4);
    len = wcslen(wname);
    wcout << wname << endl;
    // 分段倒序写入
    int sector_last = 0, pos_last = 0, num_cluster_last = 0;
    get_last_index(num_cluster_last, sector_last, pos_last);

    SetFilePointer(hDisk,                   // 文件句柄 
        offset_data + ((num_cluster_last - 2) * sector_per_cluster + sector_last) * info_disk.BytesPerSector,// 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        buffer,                             // 读入缓冲区 
        info_disk.BytesPerSector,           // 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性

    int last_pos = len - len % 13;
    int cnt_block = len / 13;
    unsigned char buffer_block[32];
    bool get_last_one = 0;
    for (int i = cnt_block; i >= 1; i--) {
        memset(buffer_block, 0, sizeof(buffer_block));
        buffer_block[0x00] = i;
        if (i == 1)
            buffer_block[0x00] |= (1 << 6);
        for (int j = 0x01; j <= 0x0A; j += 2) {
            if (last_pos + j - 0x01 >= len) {
                buffer_block[j + 1] = buffer_block[j] = 0xFF;
            }
            else {
                buffer_block[j + 1] = wname[last_pos + (j- 0x01)/2] / 256;
                buffer_block[j] = wname[last_pos + (j/2 - 0x01)/2] % 256;
            }    
        }
        buffer_block[0x0B] = 0x0F;
        buffer_block[0x0C] = 0x00;
        buffer_block[0x0D] = check_sum;
        for (int j = 0x0E; j <= 0x19; j += 2) {
            if (last_pos + j - 0x0E >= len) {
                buffer_block[j + 1] = buffer_block[j] = 0xFF;
            }
            else {
                buffer_block[j + 1] = wname[last_pos + (j - 0x0E)/2] / 256;
                buffer_block[j] = wname[last_pos + (j - 0x0E)/2] % 256;
            }
        }
        buffer_block[0x1A] = buffer_block[0x1B] = 0x00;
        for (int j = 0x1C; j <= 0x1F; j += 2) {
            if (last_pos + j - 0x1C >= len) {
                buffer_block[j + 1] = buffer_block[j] = 0xFF;
            }
            else {
                buffer_block[j + 1] = wname[last_pos + (j - 0x1C) / 2] / 256;
                buffer_block[j] = wname[last_pos + (j - 0x1C) / 2] % 256;
            }
        }
        last_pos -= 13;
        // 写回去
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + ((num_cluster_last - 2) * sector_per_cluster + sector_last) * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        bytes_write = info_disk.BytesPerSector;
        WriteFile(
            hDisk,                          // 文件句柄
            buffer,                         // 数据缓存区指针
            bytes_write,                    // 写字节数
            (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
            NULL);                          // overlap属性 
    }
}
// 创建新的短文件名 包括文件信息
void create_short_name(char* sname, unsigned char* file_info) {
    int sector_last = 0, pos_last = 0, num_cluster_last = 0;
    get_last_index(num_cluster_last, sector_last, pos_last);
    // cout << sector_last << ' ' << pos_last << endl;
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_data + ((num_cluster_last - 2) * sector_per_cluster + sector_last) * info_disk.BytesPerSector,// 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        buffer,                             // 读入缓冲区 
        info_disk.BytesPerSector,           // 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性
    memcpy(buffer + pos_last, file_info, 32);
    for (int i = 0x00; i <= 0x07; i++) {
        if (i < (int)strlen(sname))
            buffer[pos_last + i] = sname[i];
        else
            buffer[pos_last + i] = 0x20;
    }
    if (strlen(sname) > 8) {
        buffer[pos_last + 0x06] = '~';
        buffer[pos_last + 0x07] = (unsigned char)('0' + strlen(sname) - 8);
    }
    // 写回
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_data + ((num_cluster_last - 2) * sector_per_cluster + sector_last) * info_disk.BytesPerSector,// 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    bytes_write = info_disk.BytesPerSector;
    WriteFile(
        hDisk,                          // 文件句柄
        buffer,                         // 数据缓存区指针
        bytes_write,                    // 写字节数
        (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
        NULL);                          // overlap属性 
}
// 获取空的第一个文件簇编号
int get_first_cluster() {
    for (int i = 0; i < cnt_per_FAT; i++) {
        if (FAT_buffer[i] == 0)
            return i;
    }
    return -1;
}
// 复制文件簇中的内容
void copy_data(int first_cluster,int source_cluster) {
    int now_cluster = first_cluster;
    puts("正在复制文件内容...");
    for(;;) {
        // 读取并复制内容
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + (source_cluster - 2) * sector_per_cluster * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        ReadFile(hDisk,                         // 文件句柄 
            buffer_cluster,                     // 读入缓冲区 
            sector_per_cluster * info_disk.BytesPerSector,// 读入字节数 
            (LPDWORD)&bytes_read,               // 实际读取字节数指针 
            NULL);                              // overlap属性
        SetFilePointer(hDisk,                   // 文件句柄 
            offset_data + (first_cluster - 2) * sector_per_cluster * info_disk.BytesPerSector,// 低位偏移量 
            NULL,                               // 高位偏移量的指针 
            FILE_BEGIN);                        // 基准位置 
        bytes_write = sector_per_cluster * info_disk.BytesPerSector;
        WriteFile(
            hDisk,                          // 文件句柄
            buffer_cluster,                 // 数据缓存区指针
            bytes_write,                    // 写字节数
            (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
            NULL);                          // overlap属性 
        // 设置FAT表
        source_cluster = FAT_buffer[source_cluster];
        if (source_cluster == 0x0FFFFFFF) {
            FAT_buffer[first_cluster] = 0x0FFFFFFF;
            break;
        }
        now_cluster++;
        while (FAT_buffer[now_cluster] != 0) {
            now_cluster++;
        }
        FAT_buffer[first_cluster] = now_cluster;
        first_cluster = now_cluster;    
    }
    puts("正在重写FAT表...");
    // 重写FAT表 注意两个表都要写
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT,                         // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    bytes_write = cnt_per_FAT * info_disk.BytesPerSector;
    WriteFile(
        hDisk,                          // 文件句柄
        FAT_buffer,                     // 数据缓存区指针
        bytes_write,                    // 写字节数
        (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
        NULL);                          // overlap属性 
    SetFilePointer(hDisk,                   // 文件句柄 
        offset_FAT_2,                       // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    bytes_write = cnt_per_FAT * info_disk.BytesPerSector;
    WriteFile(
        hDisk,                          // 文件句柄
        FAT_buffer,                     // 数据缓存区指针
        bytes_write,                    // 写字节数
        (LPDWORD)&bytes_return,         // 用于保存实际写入字节数的存储区域的指针
        NULL);                          // overlap属性 
}


int main() {
    // 设置地区 用于unicode输入输出 
    wcin.imbue(locale(""));
    wcout.imbue(locale(""));
    // 打开磁盘 
    for (;;) {
        puts("请输入要打开的磁盘盘符:");
        char name_disk;
        cin >> name_disk;
        // 注意名字是wchar
        wchar_t name[] = L"\\\\.\\ :";
        name[4] = name_disk;
        //wcout << name << endl;
        hDisk = CreateFile(name,           // 打开盘符 
            GENERIC_READ | GENERIC_WRITE,         // 读写模式 
            FILE_SHARE_READ | FILE_SHARE_WRITE,   // 共享模式 
            NULL,                     // 安全属性 
            OPEN_EXISTING,           // 创建属性 
            0,                        // 文件属性 
            NULL);                    // 文件复制句柄 

        DeviceIoControl(
            hDisk,                         // 获取信息的句柄 
            FSCTL_DISMOUNT_VOLUME,         // 用于写磁盘 
            NULL,                          // 输入缓存 
            0,                             // 输入缓存大小 
            NULL,                          // 输出缓存 
            0,                             // 输出缓存大小 
            (LPDWORD)&bytes_return,        // 返回大小地址 
            0                              // 用于overlap 
        );

        if (hDisk == INVALID_HANDLE_VALUE) {
            puts("磁盘打开出错!");
            printf("错误代码: %d\n\n", GetLastError());
            continue;
        }
        printf("磁盘驱动器 %c 打开成功\n\n", name[4]);
        break;
    }

    // 获取磁盘信息 
    int out_buffer_size = sizeof(DISK_GEOMETRY);
    bool get_info = DeviceIoControl(
        hDisk,                         // 获取信息的句柄 
        IOCTL_DISK_GET_DRIVE_GEOMETRY, // 控制命令用于获取磁盘信息 
        NULL,                          // 输入缓存 
        0,                             // 输入缓存大小 
        (LPVOID)&info_disk,            // 输出缓存 
        (DWORD)out_buffer_size,        // 输出缓存大小 
        (LPDWORD)&bytes_return,        // 返回大小地址 
        0                              // 用于overlap 
    );
    if (!get_info) {
        puts("磁盘信息获取出错!");
        printf("错误代码: %d\n\n", GetLastError());
        return 2;
    }

    puts("磁盘信息如下:");
    cout << "柱面数 == " << info_disk.Cylinders.LowPart << endl;
    cout << "介质类型 == " << info_disk.MediaType << endl;
    cout << "每柱面磁道数 == " << info_disk.TracksPerCylinder << endl;
    cout << "每磁道扇区数 == " << info_disk.SectorsPerTrack << endl;
    cout << "每扇区字节数 == " << info_disk.BytesPerSector << endl;
    // 读取第一扇区判断是否是FAT32

    SetFilePointer(hDisk,                   // 文件句柄 
        0,                                  // 低位偏移量 
        NULL,                               // 高位偏移量的指针 
        FILE_BEGIN);                        // 基准位置 
    ReadFile(hDisk,                         // 文件句柄 
        buffer,                             // 读入缓冲区 
        info_disk.BytesPerSector,           // 读入字节数 
        (LPDWORD)&bytes_read,               // 实际读取字节数指针 
        NULL);                              // overlap属性 
    char FAT_name[9] = "FAT32   ";
    char file_system_name[9];
    memcpy(file_system_name, buffer + 0x52, 8);
    file_system_name[8] = '\0';
    if (strcmp(FAT_name, file_system_name) != 0) {
        puts("文件系统不为FAT32!");
        return 0;
    }
    puts("\n文件系统为FAT32!\n");
    // 提取根目录起始簇号、每FAT的扇区数、总扇区数、每簇扇区数、保留扇区数
    for (int i = 0x2c + 3; i >= 0x2c; i--) {
        root_first_cluster *= 256;
        root_first_cluster += buffer[i];
    }
    for (int i = 0x24 + 3; i >= 0x24; i--) {
        cnt_per_FAT *= 256;
        cnt_per_FAT += buffer[i];
    }
    int cnt_disk = 0;
    for (int i = 0x20 + 3; i >= 0x20; i--) {
        cnt_disk *= 256;
        cnt_disk += buffer[i];
    }
    sector_per_cluster = buffer[0x0D];
    int cnt_reserve = buffer[0x0F]*256 + buffer[0x0E];
    printf("每簇扇区数 == %d\n", sector_per_cluster);
    printf("总扇区数 == %d\n", cnt_disk);
    printf("每FAT的扇区数 == %d\n", cnt_per_FAT);
    printf("保留扇区数 == %d\n", cnt_reserve);
    printf("根目录起始簇号 == %d\n\n", root_first_cluster);
    
    // 计算FAT表的偏移以及数据区的偏移
    offset_FAT = cnt_reserve * info_disk.BytesPerSector;
    offset_FAT_2 = offset_FAT + cnt_per_FAT * info_disk.BytesPerSector;
    offset_data = offset_FAT + ( 2 * cnt_per_FAT + ( root_first_cluster - 2 ) * sector_per_cluster ) * info_disk.BytesPerSector;
    printf("offset_FAT == %d\n", offset_FAT);
    printf("offset_data == %d\n\n", offset_data);

    system("pause");
    system("cls");
    puts("欢迎来到磁盘管理系统 by ChenThree\n");
    puts("请输入指令:");
    puts("cls:清空屏幕");
    puts("dir:列出文件目录");
    puts("change:修改文件名(不修改后缀名)");
    puts("delete:删除文件");
    puts("copy:复制文件(不修改后缀名)");
    puts("exit:退出系统\n");

    // 每次读取操作然后进行对应操作 
    for (;;) {
        char opt[256];
        cin >> opt;

        memset(buffer, 0, sizeof(buffer));

        if (strcmp(opt, "dir") == 0) {

            wchar_t file_wname[257];
            file_wname[256] = '\0';
            int cnt_wname = 256 - 13;
            bool get_long_name = 0;
            int type = -1;

            puts("文件目录如下:");
            
            // 读FAT表
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_FAT,                         // 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                FAT_buffer,                         // 读入缓冲区 
                cnt_per_FAT * info_disk.BytesPerSector,// 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性

            int num_cluster = root_first_cluster;
            for (int cnt_sector = 0; type != 0; cnt_sector++) {
                // 根目录跨越多个文件簇的情况
                if (cnt_sector == sector_per_cluster) {
                    cnt_sector = 0;
                    if (FAT_buffer[num_cluster] == 0x0FFFFFFF) {
                        break;
                    }
                    num_cluster = FAT_buffer[num_cluster];
                }
                //cout << "now sector == " << cnt_sector << endl;
                SetFilePointer(hDisk,                   // 文件句柄 
                    offset_data + ((num_cluster - 2) * sector_per_cluster  + cnt_sector) * info_disk.BytesPerSector,// 低位偏移量 
                    NULL,                               // 高位偏移量的指针 
                    FILE_BEGIN);                        // 基准位置 
                ReadFile(hDisk,                         // 文件句柄 
                    buffer,                             // 读入缓冲区 
                    info_disk.BytesPerSector,           // 读入字节数 
                    (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                    NULL);                              // overlap属性 
                //printf_buffer(buffer, bytes_read);
                for (int pos = 0; pos < (int)info_disk.BytesPerSector; pos += 32) {
                    type = get_type(buffer + pos);
                    //cout << type << endl;
                    if (type == 1) {
                        get_long_name = 1;
                        bool first = read_long_name(buffer + pos, file_wname + cnt_wname);
                        // cout << first << endl;
                        if (first == 1) {
                            wcout << (file_wname + cnt_wname);
                            cnt_wname = 256 - 13;
                            printf("   ");
                        }
                        else cnt_wname -= 13;
                    }
                    else if (type == 2) {
                        file_info info = read_short_name(buffer + pos);
                        if (get_long_name == 0) {// 之前没有读到长文件名 
                            info.print_name();
                        }
                        else get_long_name = 0;
                        info.print_info();
                        //cout << file_sname << endl;
                    }
                    else if (type == 3) continue;
                    else break;
                }
            }
            //system("pause");
        }
        else if (strcmp(opt, "cls") == 0) {
            system("cls");
            puts("欢迎来到磁盘管理系统 by ChenThree\n");
            puts("请输入指令:");
            puts("cls:清空屏幕");
            puts("dir:列出文件目录");
            puts("change:修改文件名(不修改后缀名)");
            puts("delete:删除文件");
            puts("copy:复制文件(不修改后缀名)");
            puts("exit:退出系统\n");
        }
        else if (strcmp(opt, "change") == 0) {
            wchar_t old_wname[256];
            wchar_t new_wname[256];
            char old_sname[256];
            char new_sname[256];
            puts("请输入旧文件名:");
            wcin >> old_wname;
            puts("请输入新文件名:");
            wcin >> new_wname;
            size_t num_convert;
            wcstombs_s(&num_convert, old_sname, 256, old_wname, 256);
            _strupr_s(old_sname);
            wcstombs_s(&num_convert, new_sname, 256, new_wname, 256);
            _strupr_s(new_sname);
            //wcout << old_wname << ' '; 
            //cout << old_sname << endl;
            //wcout << new_wname << ' '; 
            //cout << new_sname << endl;
            
            // 读FAT表
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_FAT,                         // 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                FAT_buffer,                         // 读入缓冲区 
                cnt_per_FAT * info_disk.BytesPerSector,// 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性

            // 查找新旧文件名存不存在 存在的话返回位置 方便计算
            int old_sector_on = 0, old_pos_on = 0, old_num_cluster = 0;
            int new_sector_on = 0, new_pos_on = 0, new_num_cluster = 0;
            bool exist_old = search_file_name(old_wname, old_sname, old_num_cluster, old_sector_on, old_pos_on);
            if (exist_old == 0) {
                puts("文件名不存在!");
                continue;
            }
            bool exist_new = search_file_name(new_wname, new_sname, new_num_cluster, new_sector_on, new_pos_on);
            if (exist_new == 1) {
                puts("新文件名已经存在!");
                continue;
            }
            //cout << exist_old << ' ' << exist_new << endl;

            // 删除旧的文件名
            puts("正在删除旧文件名...");
            delete_file_name(old_wname, old_sname, old_num_cluster, old_sector_on, old_pos_on);
            // 将短文件名中的信息读取下来
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_data + ((old_num_cluster - 2) * sector_per_cluster + old_sector_on) * info_disk.BytesPerSector,// 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                buffer,                             // 读入缓冲区 
                info_disk.BytesPerSector,           // 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性
            unsigned char old_file_data[32];
            memcpy(old_file_data, buffer + old_pos_on, 32);
            // 创建新的文件名
            puts("正在创建新文件名...");
            if (strlen(new_sname) > 8) {
                // create_long_name(new_wname, new_sname, old_file_data);
            }
            create_short_name(new_sname, old_file_data);
            puts("重命名完毕!");
        }
        else if (strcmp(opt, "delete") == 0) {
            wchar_t file_wname[256];
            char file_sname[256];
            puts("请输入要删除的文件名:");
            wcin >> file_wname;
            size_t num_convert;
            wcstombs_s(&num_convert, file_sname, 256, file_wname, 256);
            _strupr_s(file_sname);
            // 读FAT表
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_FAT,                         // 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                FAT_buffer,                         // 读入缓冲区 
                cnt_per_FAT* info_disk.BytesPerSector,// 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性
            // 先查找文件是否存在
            int sector_on = 0, pos_on = 0, num_cluster = 0;
            bool file_exist = delete_file_name(file_wname, file_sname, num_cluster, sector_on, pos_on);
            // 读取文件簇信息
            if (file_exist == 1) {
                SetFilePointer(hDisk,                   // 文件句柄 
                    offset_data + ((num_cluster - 2) * sector_per_cluster + sector_on) * info_disk.BytesPerSector,// 低位偏移量 
                    NULL,                               // 高位偏移量的指针 
                    FILE_BEGIN);                        // 基准位置 
                ReadFile(hDisk,                         // 文件句柄 
                    buffer,                             // 读入缓冲区 
                    info_disk.BytesPerSector,           // 读入字节数 
                    (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                    NULL);                              // overlap属性 
                file_info info = read_short_name(buffer + pos_on);
                //info.print_name();
                //info.print_info();
                delete_file_data(info);
            }
            else {
                puts("文件不存在!");
                continue;
            }
        }
        else if ((strcmp(opt, "copy") == 0)) {
            wchar_t file_wname[256];
            char file_sname[256];
            puts("请输入要复制的文件名:");
            wcin >> file_wname;
            size_t num_convert;
            wcstombs_s(&num_convert, file_sname, 256, file_wname, 256);
            _strupr_s(file_sname);

            wchar_t new_wname[256];
            char new_sname[256];
            puts("请输入复制后的新文件名:");
            wcin >> new_wname;
            wcstombs_s(&num_convert, new_sname, 256, new_wname, 256);
            _strupr_s(new_sname);

            // 读FAT表
            SetFilePointer(hDisk,                   // 文件句柄 
                offset_FAT,                         // 低位偏移量 
                NULL,                               // 高位偏移量的指针 
                FILE_BEGIN);                        // 基准位置 
            ReadFile(hDisk,                         // 文件句柄 
                FAT_buffer,                         // 读入缓冲区 
                cnt_per_FAT* info_disk.BytesPerSector,// 读入字节数 
                (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                NULL);                              // overlap属性

            // 先查找文件是否存在
            int sector_on = 0, pos_on = 0, num_cluster = 0;
            bool file_exist = search_file_name(file_wname, file_sname, num_cluster, sector_on, pos_on);
            unsigned char file_info[32];
            memset(file_info, 0, sizeof(file_info));
            // 读取文件簇信息
            if (file_exist == 1) {
                SetFilePointer(hDisk,                   // 文件句柄 
                    offset_data + ((num_cluster - 2) * sector_per_cluster + sector_on) * info_disk.BytesPerSector,// 低位偏移量 
                    NULL,                               // 高位偏移量的指针 
                    FILE_BEGIN);                        // 基准位置 
                ReadFile(hDisk,                         // 文件句柄 
                    buffer,                             // 读入缓冲区 
                    info_disk.BytesPerSector,           // 读入字节数 
                    (LPDWORD)&bytes_read,               // 实际读取字节数指针 
                    NULL);                              // overlap属性 
                if (get_type(buffer + pos_on) == 1) {// 长文件名
                    if (pos_on == buffer_size - 32) {
                        pos_on = 0;
                        sector_on++;
                    }
                    else {
                        pos_on += 32;
                    }        
                }
                memcpy(file_info, buffer + pos_on, 32);
                // info.print_name();
                // info.print_info();
            }
            else {    
                puts("文件不存在!");
                continue;
            }
            
            int new_sector_on = 0, new_pos_on = 0, new_num_cluster = 0;
            bool exist_new = search_file_name(new_wname, new_sname, new_num_cluster, new_sector_on, new_pos_on);
            if (exist_new == 1) {
                puts("新文件名已经存在!");
                continue;
            }
            // 修改新文件首文件簇
            int source_cluster = file_info[0x1A] + file_info[0x1B] * 256;
            int first_cluster = get_first_cluster();
            file_info[0x1A] = first_cluster % 256;
            file_info[0x1B] = first_cluster / 256;
            if (strlen(new_sname) > 8) {
                // create_long_name(new_wname, new_sname, old_file_data);
            }
            create_short_name(new_sname, file_info);
            copy_data(first_cluster,source_cluster);
            puts("文件复制完成!");
        }
        else if ((strcmp(opt, "exit") == 0)) {
            break;
        }
        else {
            puts("未知指令,请重新输入!");
            //system("pause");
        }
    }

    return 0;
}
Last modification:June 8th, 2020 at 01:44 pm
如果觉得我的文章对你有用,请随意赞赏