Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
source/daplink/drag-n-drop/virtual_fs.c@0:01f31e923fe2, 2020-04-07 (annotated)
- Committer:
- Pawel Zarembski
- Date:
- Tue Apr 07 12:55:42 2020 +0200
- Revision:
- 0:01f31e923fe2
hani: DAPLink with reset workaround
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Pawel Zarembski |
0:01f31e923fe2 | 1 | /** |
Pawel Zarembski |
0:01f31e923fe2 | 2 | * @file virtual_fs.c |
Pawel Zarembski |
0:01f31e923fe2 | 3 | * @brief Implementation of virtual_fs.h |
Pawel Zarembski |
0:01f31e923fe2 | 4 | * |
Pawel Zarembski |
0:01f31e923fe2 | 5 | * DAPLink Interface Firmware |
Pawel Zarembski |
0:01f31e923fe2 | 6 | * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved |
Pawel Zarembski |
0:01f31e923fe2 | 7 | * SPDX-License-Identifier: Apache-2.0 |
Pawel Zarembski |
0:01f31e923fe2 | 8 | * |
Pawel Zarembski |
0:01f31e923fe2 | 9 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
Pawel Zarembski |
0:01f31e923fe2 | 10 | * not use this file except in compliance with the License. |
Pawel Zarembski |
0:01f31e923fe2 | 11 | * You may obtain a copy of the License at |
Pawel Zarembski |
0:01f31e923fe2 | 12 | * |
Pawel Zarembski |
0:01f31e923fe2 | 13 | * http://www.apache.org/licenses/LICENSE-2.0 |
Pawel Zarembski |
0:01f31e923fe2 | 14 | * |
Pawel Zarembski |
0:01f31e923fe2 | 15 | * Unless required by applicable law or agreed to in writing, software |
Pawel Zarembski |
0:01f31e923fe2 | 16 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
Pawel Zarembski |
0:01f31e923fe2 | 17 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Pawel Zarembski |
0:01f31e923fe2 | 18 | * See the License for the specific language governing permissions and |
Pawel Zarembski |
0:01f31e923fe2 | 19 | * limitations under the License. |
Pawel Zarembski |
0:01f31e923fe2 | 20 | */ |
Pawel Zarembski |
0:01f31e923fe2 | 21 | |
Pawel Zarembski |
0:01f31e923fe2 | 22 | #include <string.h> |
Pawel Zarembski |
0:01f31e923fe2 | 23 | |
Pawel Zarembski |
0:01f31e923fe2 | 24 | #include "virtual_fs.h" |
Pawel Zarembski |
0:01f31e923fe2 | 25 | #include "info.h" |
Pawel Zarembski |
0:01f31e923fe2 | 26 | #include "settings.h" |
Pawel Zarembski |
0:01f31e923fe2 | 27 | #include "compiler.h" |
Pawel Zarembski |
0:01f31e923fe2 | 28 | #include "util.h" |
Pawel Zarembski |
0:01f31e923fe2 | 29 | |
Pawel Zarembski |
0:01f31e923fe2 | 30 | // Virtual file system driver |
Pawel Zarembski |
0:01f31e923fe2 | 31 | // Limitations: |
Pawel Zarembski |
0:01f31e923fe2 | 32 | // - files must be contiguous |
Pawel Zarembski |
0:01f31e923fe2 | 33 | // - data written cannot be read back |
Pawel Zarembski |
0:01f31e923fe2 | 34 | // - data should only be read once |
Pawel Zarembski |
0:01f31e923fe2 | 35 | |
Pawel Zarembski |
0:01f31e923fe2 | 36 | // FAT16 limitations +- safety margin |
Pawel Zarembski |
0:01f31e923fe2 | 37 | #define FAT_CLUSTERS_MAX (65525 - 100) |
Pawel Zarembski |
0:01f31e923fe2 | 38 | #define FAT_CLUSTERS_MIN (4086 + 100) |
Pawel Zarembski |
0:01f31e923fe2 | 39 | |
Pawel Zarembski |
0:01f31e923fe2 | 40 | typedef struct { |
Pawel Zarembski |
0:01f31e923fe2 | 41 | uint8_t boot_sector[11]; |
Pawel Zarembski |
0:01f31e923fe2 | 42 | /* DOS 2.0 BPB - Bios Parameter Block, 11 bytes */ |
Pawel Zarembski |
0:01f31e923fe2 | 43 | uint16_t bytes_per_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 44 | uint8_t sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 45 | uint16_t reserved_logical_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 46 | uint8_t num_fats; |
Pawel Zarembski |
0:01f31e923fe2 | 47 | uint16_t max_root_dir_entries; |
Pawel Zarembski |
0:01f31e923fe2 | 48 | uint16_t total_logical_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 49 | uint8_t media_descriptor; |
Pawel Zarembski |
0:01f31e923fe2 | 50 | uint16_t logical_sectors_per_fat; |
Pawel Zarembski |
0:01f31e923fe2 | 51 | /* DOS 3.31 BPB - Bios Parameter Block, 12 bytes */ |
Pawel Zarembski |
0:01f31e923fe2 | 52 | uint16_t physical_sectors_per_track; |
Pawel Zarembski |
0:01f31e923fe2 | 53 | uint16_t heads; |
Pawel Zarembski |
0:01f31e923fe2 | 54 | uint32_t hidden_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 55 | uint32_t big_sectors_on_drive; |
Pawel Zarembski |
0:01f31e923fe2 | 56 | /* Extended BIOS Parameter Block, 26 bytes */ |
Pawel Zarembski |
0:01f31e923fe2 | 57 | uint8_t physical_drive_number; |
Pawel Zarembski |
0:01f31e923fe2 | 58 | uint8_t not_used; |
Pawel Zarembski |
0:01f31e923fe2 | 59 | uint8_t boot_record_signature; |
Pawel Zarembski |
0:01f31e923fe2 | 60 | uint32_t volume_id; |
Pawel Zarembski |
0:01f31e923fe2 | 61 | char volume_label[11]; |
Pawel Zarembski |
0:01f31e923fe2 | 62 | char file_system_type[8]; |
Pawel Zarembski |
0:01f31e923fe2 | 63 | /* bootstrap data in bytes 62-509 */ |
Pawel Zarembski |
0:01f31e923fe2 | 64 | uint8_t bootstrap[448]; |
Pawel Zarembski |
0:01f31e923fe2 | 65 | /* These entries in place of bootstrap code are the *nix partitions */ |
Pawel Zarembski |
0:01f31e923fe2 | 66 | //uint8_t partition_one[16]; |
Pawel Zarembski |
0:01f31e923fe2 | 67 | //uint8_t partition_two[16]; |
Pawel Zarembski |
0:01f31e923fe2 | 68 | //uint8_t partition_three[16]; |
Pawel Zarembski |
0:01f31e923fe2 | 69 | //uint8_t partition_four[16]; |
Pawel Zarembski |
0:01f31e923fe2 | 70 | /* Mandatory value at bytes 510-511, must be 0xaa55 */ |
Pawel Zarembski |
0:01f31e923fe2 | 71 | uint16_t signature; |
Pawel Zarembski |
0:01f31e923fe2 | 72 | } __attribute__((packed)) mbr_t; |
Pawel Zarembski |
0:01f31e923fe2 | 73 | |
Pawel Zarembski |
0:01f31e923fe2 | 74 | typedef struct file_allocation_table { |
Pawel Zarembski |
0:01f31e923fe2 | 75 | uint8_t f[512]; |
Pawel Zarembski |
0:01f31e923fe2 | 76 | } file_allocation_table_t; |
Pawel Zarembski |
0:01f31e923fe2 | 77 | |
Pawel Zarembski |
0:01f31e923fe2 | 78 | typedef struct FatDirectoryEntry { |
Pawel Zarembski |
0:01f31e923fe2 | 79 | vfs_filename_t filename; |
Pawel Zarembski |
0:01f31e923fe2 | 80 | uint8_t attributes; |
Pawel Zarembski |
0:01f31e923fe2 | 81 | uint8_t reserved; |
Pawel Zarembski |
0:01f31e923fe2 | 82 | uint8_t creation_time_ms; |
Pawel Zarembski |
0:01f31e923fe2 | 83 | uint16_t creation_time; |
Pawel Zarembski |
0:01f31e923fe2 | 84 | uint16_t creation_date; |
Pawel Zarembski |
0:01f31e923fe2 | 85 | uint16_t accessed_date; |
Pawel Zarembski |
0:01f31e923fe2 | 86 | uint16_t first_cluster_high_16; |
Pawel Zarembski |
0:01f31e923fe2 | 87 | uint16_t modification_time; |
Pawel Zarembski |
0:01f31e923fe2 | 88 | uint16_t modification_date; |
Pawel Zarembski |
0:01f31e923fe2 | 89 | uint16_t first_cluster_low_16; |
Pawel Zarembski |
0:01f31e923fe2 | 90 | uint32_t filesize; |
Pawel Zarembski |
0:01f31e923fe2 | 91 | } __attribute__((packed)) FatDirectoryEntry_t; |
Pawel Zarembski |
0:01f31e923fe2 | 92 | COMPILER_ASSERT(sizeof(FatDirectoryEntry_t) == 32); |
Pawel Zarembski |
0:01f31e923fe2 | 93 | |
Pawel Zarembski |
0:01f31e923fe2 | 94 | // to save RAM all files must be in the first root dir entry (512 bytes) |
Pawel Zarembski |
0:01f31e923fe2 | 95 | // but 2 actually exist on disc (32 entries) to accomodate hidden OS files, |
Pawel Zarembski |
0:01f31e923fe2 | 96 | // folders and metadata |
Pawel Zarembski |
0:01f31e923fe2 | 97 | typedef struct root_dir { |
Pawel Zarembski |
0:01f31e923fe2 | 98 | FatDirectoryEntry_t f[32]; |
Pawel Zarembski |
0:01f31e923fe2 | 99 | } root_dir_t; |
Pawel Zarembski |
0:01f31e923fe2 | 100 | |
Pawel Zarembski |
0:01f31e923fe2 | 101 | typedef struct virtual_media { |
Pawel Zarembski |
0:01f31e923fe2 | 102 | vfs_read_cb_t read_cb; |
Pawel Zarembski |
0:01f31e923fe2 | 103 | vfs_write_cb_t write_cb; |
Pawel Zarembski |
0:01f31e923fe2 | 104 | uint32_t length; |
Pawel Zarembski |
0:01f31e923fe2 | 105 | } virtual_media_t; |
Pawel Zarembski |
0:01f31e923fe2 | 106 | |
Pawel Zarembski |
0:01f31e923fe2 | 107 | static uint32_t read_zero(uint32_t offset, uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 108 | static void write_none(uint32_t offset, const uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 109 | |
Pawel Zarembski |
0:01f31e923fe2 | 110 | static uint32_t read_mbr(uint32_t offset, uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 111 | static uint32_t read_fat(uint32_t offset, uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 112 | static uint32_t read_dir(uint32_t offset, uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 113 | static void write_dir(uint32_t offset, const uint8_t *data, uint32_t size); |
Pawel Zarembski |
0:01f31e923fe2 | 114 | static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change, |
Pawel Zarembski |
0:01f31e923fe2 | 115 | vfs_file_t file, vfs_file_t new_file_data); |
Pawel Zarembski |
0:01f31e923fe2 | 116 | static uint32_t cluster_to_sector(uint32_t cluster_idx); |
Pawel Zarembski |
0:01f31e923fe2 | 117 | static bool filename_valid(const vfs_filename_t filename); |
Pawel Zarembski |
0:01f31e923fe2 | 118 | static bool filename_character_valid(char character); |
Pawel Zarembski |
0:01f31e923fe2 | 119 | |
Pawel Zarembski |
0:01f31e923fe2 | 120 | // If sector size changes update comment below |
Pawel Zarembski |
0:01f31e923fe2 | 121 | COMPILER_ASSERT(0x0200 == VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 122 | // If root directory size changes update max_root_dir_entries |
Pawel Zarembski |
0:01f31e923fe2 | 123 | COMPILER_ASSERT(0x0020 == sizeof(root_dir_t) / sizeof(FatDirectoryEntry_t)); |
Pawel Zarembski |
0:01f31e923fe2 | 124 | static const mbr_t mbr_tmpl = { |
Pawel Zarembski |
0:01f31e923fe2 | 125 | /*uint8_t[11]*/.boot_sector = { |
Pawel Zarembski |
0:01f31e923fe2 | 126 | 0xEB, 0x3C, 0x90, |
Pawel Zarembski |
0:01f31e923fe2 | 127 | 'M', 'S', 'D', '0', 'S', '4', '.', '1' // OEM Name in text (8 chars max) |
Pawel Zarembski |
0:01f31e923fe2 | 128 | }, |
Pawel Zarembski |
0:01f31e923fe2 | 129 | /*uint16_t*/.bytes_per_sector = 0x0200, // 512 bytes per sector |
Pawel Zarembski |
0:01f31e923fe2 | 130 | /*uint8_t */.sectors_per_cluster = 0x08, // 4k cluser |
Pawel Zarembski |
0:01f31e923fe2 | 131 | /*uint16_t*/.reserved_logical_sectors = 0x0001, // mbr is 1 sector |
Pawel Zarembski |
0:01f31e923fe2 | 132 | /*uint8_t */.num_fats = 0x02, // 2 FATs |
Pawel Zarembski |
0:01f31e923fe2 | 133 | /*uint16_t*/.max_root_dir_entries = 0x0020, // 32 dir entries (max) |
Pawel Zarembski |
0:01f31e923fe2 | 134 | /*uint16_t*/.total_logical_sectors = 0x1f50, // sector size * # of sectors = drive size |
Pawel Zarembski |
0:01f31e923fe2 | 135 | /*uint8_t */.media_descriptor = 0xf8, // fixed disc = F8, removable = F0 |
Pawel Zarembski |
0:01f31e923fe2 | 136 | /*uint16_t*/.logical_sectors_per_fat = 0x0001, // FAT is 1k - ToDO:need to edit this |
Pawel Zarembski |
0:01f31e923fe2 | 137 | /*uint16_t*/.physical_sectors_per_track = 0x0001, // flat |
Pawel Zarembski |
0:01f31e923fe2 | 138 | /*uint16_t*/.heads = 0x0001, // flat |
Pawel Zarembski |
0:01f31e923fe2 | 139 | /*uint32_t*/.hidden_sectors = 0x00000000, // before mbt, 0 |
Pawel Zarembski |
0:01f31e923fe2 | 140 | /*uint32_t*/.big_sectors_on_drive = 0x00000000, // 4k sector. not using large clusters |
Pawel Zarembski |
0:01f31e923fe2 | 141 | /*uint8_t */.physical_drive_number = 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 142 | /*uint8_t */.not_used = 0x00, // Current head. Linux tries to set this to 0x1 |
Pawel Zarembski |
0:01f31e923fe2 | 143 | /*uint8_t */.boot_record_signature = 0x29, // signature is present |
Pawel Zarembski |
0:01f31e923fe2 | 144 | /*uint32_t*/.volume_id = 0x27021974, // serial number |
Pawel Zarembski |
0:01f31e923fe2 | 145 | // needs to match the root dir label |
Pawel Zarembski |
0:01f31e923fe2 | 146 | /*char[11]*/.volume_label = {'D', 'A', 'P', 'L', 'I', 'N', 'K', '-', 'D', 'N', 'D'}, |
Pawel Zarembski |
0:01f31e923fe2 | 147 | // unused by msft - just a label (FAT, FAT12, FAT16) |
Pawel Zarembski |
0:01f31e923fe2 | 148 | /*char[8] */.file_system_type = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}, |
Pawel Zarembski |
0:01f31e923fe2 | 149 | |
Pawel Zarembski |
0:01f31e923fe2 | 150 | /* BOOTSTRAP SOURCE CODE AND PAYLOAD GENERATOR |
Pawel Zarembski |
0:01f31e923fe2 | 151 | * PRINTS OUT WARNING MESSAGE ON ACCIDENTAL BOOT FROM DAPLINK |
Pawel Zarembski |
0:01f31e923fe2 | 152 | 1 [BITS 16] |
Pawel Zarembski |
0:01f31e923fe2 | 153 | 2 %define BLSTART 0x3E |
Pawel Zarembski |
0:01f31e923fe2 | 154 | 3 %define BLLEN 448 |
Pawel Zarembski |
0:01f31e923fe2 | 155 | 4 |
Pawel Zarembski |
0:01f31e923fe2 | 156 | 5 00000000 FA cli |
Pawel Zarembski |
0:01f31e923fe2 | 157 | 6 00000001 B8C007 mov ax, 07C0h |
Pawel Zarembski |
0:01f31e923fe2 | 158 | 7 00000004 052001 add ax, 288 |
Pawel Zarembski |
0:01f31e923fe2 | 159 | 8 00000007 8ED0 mov ss, ax |
Pawel Zarembski |
0:01f31e923fe2 | 160 | 9 00000009 BC0010 mov sp, 4096 |
Pawel Zarembski |
0:01f31e923fe2 | 161 | 10 0000000C B8C007 mov ax, 07C0h |
Pawel Zarembski |
0:01f31e923fe2 | 162 | 11 0000000F 8ED8 mov ds, ax |
Pawel Zarembski |
0:01f31e923fe2 | 163 | 12 00000011 BE[6D00] mov si,message+BLSTART |
Pawel Zarembski |
0:01f31e923fe2 | 164 | 13 00000014 E80B00 call print |
Pawel Zarembski |
0:01f31e923fe2 | 165 | 14 00000017 EBFE jmp $ |
Pawel Zarembski |
0:01f31e923fe2 | 166 | 15 |
Pawel Zarembski |
0:01f31e923fe2 | 167 | 16 printc: |
Pawel Zarembski |
0:01f31e923fe2 | 168 | 17 00000019 B40E mov ah, 0x0E |
Pawel Zarembski |
0:01f31e923fe2 | 169 | 18 0000001B B700 mov bh, 0x00 |
Pawel Zarembski |
0:01f31e923fe2 | 170 | 19 0000001D B307 mov bl, 0x07 |
Pawel Zarembski |
0:01f31e923fe2 | 171 | 20 0000001F CD10 int 0x10 |
Pawel Zarembski |
0:01f31e923fe2 | 172 | 21 00000021 C3 ret |
Pawel Zarembski |
0:01f31e923fe2 | 173 | 22 |
Pawel Zarembski |
0:01f31e923fe2 | 174 | 23 print: |
Pawel Zarembski |
0:01f31e923fe2 | 175 | 24 nextc: |
Pawel Zarembski |
0:01f31e923fe2 | 176 | 25 00000022 8A04 mov al, [si] |
Pawel Zarembski |
0:01f31e923fe2 | 177 | 26 00000024 46 inc si |
Pawel Zarembski |
0:01f31e923fe2 | 178 | 27 00000025 08C0 or al, al |
Pawel Zarembski |
0:01f31e923fe2 | 179 | 28 00000027 7405 jz return |
Pawel Zarembski |
0:01f31e923fe2 | 180 | 29 00000029 E8EDFF call printc |
Pawel Zarembski |
0:01f31e923fe2 | 181 | 30 0000002C EBF4 jmp nextc |
Pawel Zarembski |
0:01f31e923fe2 | 182 | 31 return: |
Pawel Zarembski |
0:01f31e923fe2 | 183 | 32 0000002E C3 ret |
Pawel Zarembski |
0:01f31e923fe2 | 184 | 33 |
Pawel Zarembski |
0:01f31e923fe2 | 185 | 34 0000002F 504C45415345205245- message db 'PLEASE REMOVE THE ARM MBED DAPLINK USB DEVICE AND REBOOT THE SYSTEM..', 0 |
Pawel Zarembski |
0:01f31e923fe2 | 186 | 35 00000038 4D4F56452054484520- |
Pawel Zarembski |
0:01f31e923fe2 | 187 | 36 00000041 41524D204D42454420- |
Pawel Zarembski |
0:01f31e923fe2 | 188 | 37 0000004A 4441504C494E4B2055- |
Pawel Zarembski |
0:01f31e923fe2 | 189 | 38 00000053 534220444556494345- |
Pawel Zarembski |
0:01f31e923fe2 | 190 | 39 0000005C 20414E44205245424F- |
Pawel Zarembski |
0:01f31e923fe2 | 191 | 40 00000065 4F5420544845205359- |
Pawel Zarembski |
0:01f31e923fe2 | 192 | 41 0000006E 5354454D2E2E00 |
Pawel Zarembski |
0:01f31e923fe2 | 193 | 42 |
Pawel Zarembski |
0:01f31e923fe2 | 194 | 43 00000075 00<rept> times BLLEN-($-$$) db 0 |
Pawel Zarembski |
0:01f31e923fe2 | 195 | |
Pawel Zarembski |
0:01f31e923fe2 | 196 | USE BELOW SCRIPT TO COMPILE BOOTSTRAP AND GENERATE PAYLOAD: |
Pawel Zarembski |
0:01f31e923fe2 | 197 | #!/usr/bin/env python |
Pawel Zarembski |
0:01f31e923fe2 | 198 | import os |
Pawel Zarembski |
0:01f31e923fe2 | 199 | os.system('nasm -f bin -o print.bin -l print.lst print.asm') |
Pawel Zarembski |
0:01f31e923fe2 | 200 | print(open('print.lst','r').read()) |
Pawel Zarembski |
0:01f31e923fe2 | 201 | x=1 |
Pawel Zarembski |
0:01f31e923fe2 | 202 | for c in open('print.bin','rb').read(): |
Pawel Zarembski |
0:01f31e923fe2 | 203 | print('0x%02X, '%c, end='' if x % 16 else '\n') |
Pawel Zarembski |
0:01f31e923fe2 | 204 | x += 1 |
Pawel Zarembski |
0:01f31e923fe2 | 205 | */ |
Pawel Zarembski |
0:01f31e923fe2 | 206 | /*uint8_t[448]*/.bootstrap = { |
Pawel Zarembski |
0:01f31e923fe2 | 207 | 0xFA, 0xB8, 0xC0, 0x07, 0x05, 0x20, 0x01, 0x8E, 0xD0, 0xBC, 0x00, 0x10, 0xB8, 0xC0, 0x07, 0x8E, |
Pawel Zarembski |
0:01f31e923fe2 | 208 | 0xD8, 0xBE, 0x6D, 0x00, 0xE8, 0x0B, 0x00, 0xEB, 0xFE, 0xB4, 0x0E, 0xB7, 0x00, 0xB3, 0x07, 0xCD, |
Pawel Zarembski |
0:01f31e923fe2 | 209 | 0x10, 0xC3, 0x8A, 0x04, 0x46, 0x08, 0xC0, 0x74, 0x05, 0xE8, 0xED, 0xFF, 0xEB, 0xF4, 0xC3, 0x50, |
Pawel Zarembski |
0:01f31e923fe2 | 210 | 0x4C, 0x45, 0x41, 0x53, 0x45, 0x20, 0x52, 0x45, 0x4D, 0x4F, 0x56, 0x45, 0x20, 0x54, 0x48, 0x45, |
Pawel Zarembski |
0:01f31e923fe2 | 211 | 0x20, 0x41, 0x52, 0x4D, 0x20, 0x4D, 0x42, 0x45, 0x44, 0x20, 0x44, 0x41, 0x50, 0x4C, 0x49, 0x4E, |
Pawel Zarembski |
0:01f31e923fe2 | 212 | 0x4B, 0x20, 0x55, 0x53, 0x42, 0x20, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x20, 0x41, 0x4E, 0x44, |
Pawel Zarembski |
0:01f31e923fe2 | 213 | 0x20, 0x52, 0x45, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x59, 0x53, 0x54, |
Pawel Zarembski |
0:01f31e923fe2 | 214 | 0x45, 0x4D, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 235 | }, |
Pawel Zarembski |
0:01f31e923fe2 | 236 | // Signature MUST be 0xAA55 to maintain compatibility (i.e. with Android). |
Pawel Zarembski |
0:01f31e923fe2 | 237 | /*uint16_t*/.signature = 0xAA55, |
Pawel Zarembski |
0:01f31e923fe2 | 238 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 239 | |
Pawel Zarembski |
0:01f31e923fe2 | 240 | enum virtual_media_idx_t { |
Pawel Zarembski |
0:01f31e923fe2 | 241 | MEDIA_IDX_MBR = 0, |
Pawel Zarembski |
0:01f31e923fe2 | 242 | MEDIA_IDX_FAT1, |
Pawel Zarembski |
0:01f31e923fe2 | 243 | MEDIA_IDX_FAT2, |
Pawel Zarembski |
0:01f31e923fe2 | 244 | MEDIA_IDX_ROOT_DIR, |
Pawel Zarembski |
0:01f31e923fe2 | 245 | |
Pawel Zarembski |
0:01f31e923fe2 | 246 | MEDIA_IDX_COUNT |
Pawel Zarembski |
0:01f31e923fe2 | 247 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 248 | |
Pawel Zarembski |
0:01f31e923fe2 | 249 | // Note - everything in virtual media must be a multiple of VFS_SECTOR_SIZE |
Pawel Zarembski |
0:01f31e923fe2 | 250 | const virtual_media_t virtual_media_tmpl[] = { |
Pawel Zarembski |
0:01f31e923fe2 | 251 | /* Read CB Write CB Region Size Region Name */ |
Pawel Zarembski |
0:01f31e923fe2 | 252 | { read_mbr, write_none, VFS_SECTOR_SIZE }, /* MBR */ |
Pawel Zarembski |
0:01f31e923fe2 | 253 | { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT1 */ |
Pawel Zarembski |
0:01f31e923fe2 | 254 | { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT2 */ |
Pawel Zarembski |
0:01f31e923fe2 | 255 | { read_dir, write_dir, VFS_SECTOR_SIZE * 2 }, /* Root Dir */ |
Pawel Zarembski |
0:01f31e923fe2 | 256 | /* Raw filesystem contents follow */ |
Pawel Zarembski |
0:01f31e923fe2 | 257 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 258 | // Keep virtual_media_idx_t in sync with virtual_media_tmpl |
Pawel Zarembski |
0:01f31e923fe2 | 259 | COMPILER_ASSERT(MEDIA_IDX_COUNT == ARRAY_SIZE(virtual_media_tmpl)); |
Pawel Zarembski |
0:01f31e923fe2 | 260 | |
Pawel Zarembski |
0:01f31e923fe2 | 261 | static const FatDirectoryEntry_t root_dir_entry = { |
Pawel Zarembski |
0:01f31e923fe2 | 262 | /*uint8_t[11] */ .filename = {""}, |
Pawel Zarembski |
0:01f31e923fe2 | 263 | /*uint8_t */ .attributes = VFS_FILE_ATTR_VOLUME_LABEL | VFS_FILE_ATTR_ARCHIVE, |
Pawel Zarembski |
0:01f31e923fe2 | 264 | /*uint8_t */ .reserved = 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 265 | /*uint8_t */ .creation_time_ms = 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 266 | /*uint16_t*/ .creation_time = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 267 | /*uint16_t*/ .creation_date = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 268 | /*uint16_t*/ .accessed_date = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 269 | /*uint16_t*/ .first_cluster_high_16 = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 270 | /*uint16_t*/ .modification_time = 0x8E41, |
Pawel Zarembski |
0:01f31e923fe2 | 271 | /*uint16_t*/ .modification_date = 0x32bb, |
Pawel Zarembski |
0:01f31e923fe2 | 272 | /*uint16_t*/ .first_cluster_low_16 = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 273 | /*uint32_t*/ .filesize = 0x00000000 |
Pawel Zarembski |
0:01f31e923fe2 | 274 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 275 | |
Pawel Zarembski |
0:01f31e923fe2 | 276 | static const FatDirectoryEntry_t dir_entry_tmpl = { |
Pawel Zarembski |
0:01f31e923fe2 | 277 | /*uint8_t[11] */ .filename = {""}, |
Pawel Zarembski |
0:01f31e923fe2 | 278 | /*uint8_t */ .attributes = VFS_FILE_ATTR_READ_ONLY, |
Pawel Zarembski |
0:01f31e923fe2 | 279 | /*uint8_t */ .reserved = 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 280 | /*uint8_t */ .creation_time_ms = 0x00, |
Pawel Zarembski |
0:01f31e923fe2 | 281 | /*uint16_t*/ .creation_time = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 282 | /*uint16_t*/ .creation_date = 0x4876, |
Pawel Zarembski |
0:01f31e923fe2 | 283 | /*uint16_t*/ .accessed_date = 0x4876, |
Pawel Zarembski |
0:01f31e923fe2 | 284 | /*uint16_t*/ .first_cluster_high_16 = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 285 | /*uint16_t*/ .modification_time = 0x83dc, |
Pawel Zarembski |
0:01f31e923fe2 | 286 | /*uint16_t*/ .modification_date = 0x4876, |
Pawel Zarembski |
0:01f31e923fe2 | 287 | /*uint16_t*/ .first_cluster_low_16 = 0x0000, |
Pawel Zarembski |
0:01f31e923fe2 | 288 | /*uint32_t*/ .filesize = 0x00000000 |
Pawel Zarembski |
0:01f31e923fe2 | 289 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 290 | |
Pawel Zarembski |
0:01f31e923fe2 | 291 | mbr_t mbr; |
Pawel Zarembski |
0:01f31e923fe2 | 292 | file_allocation_table_t fat; |
Pawel Zarembski |
0:01f31e923fe2 | 293 | virtual_media_t virtual_media[16]; |
Pawel Zarembski |
0:01f31e923fe2 | 294 | root_dir_t dir_current; |
Pawel Zarembski |
0:01f31e923fe2 | 295 | uint8_t file_count; |
Pawel Zarembski |
0:01f31e923fe2 | 296 | vfs_file_change_cb_t file_change_cb; |
Pawel Zarembski |
0:01f31e923fe2 | 297 | uint32_t virtual_media_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 298 | uint32_t fat_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 299 | uint32_t dir_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 300 | uint32_t data_start; |
Pawel Zarembski |
0:01f31e923fe2 | 301 | |
Pawel Zarembski |
0:01f31e923fe2 | 302 | // Virtual media must be larger than the template |
Pawel Zarembski |
0:01f31e923fe2 | 303 | COMPILER_ASSERT(sizeof(virtual_media) > sizeof(virtual_media_tmpl)); |
Pawel Zarembski |
0:01f31e923fe2 | 304 | |
Pawel Zarembski |
0:01f31e923fe2 | 305 | static void write_fat(file_allocation_table_t *fat, uint32_t idx, uint16_t val) |
Pawel Zarembski |
0:01f31e923fe2 | 306 | { |
Pawel Zarembski |
0:01f31e923fe2 | 307 | uint32_t low_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 308 | uint32_t high_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 309 | low_idx = idx * 2 + 0; |
Pawel Zarembski |
0:01f31e923fe2 | 310 | high_idx = idx * 2 + 1; |
Pawel Zarembski |
0:01f31e923fe2 | 311 | |
Pawel Zarembski |
0:01f31e923fe2 | 312 | // Assert that this is still within the fat table |
Pawel Zarembski |
0:01f31e923fe2 | 313 | if (high_idx >= ARRAY_SIZE(fat->f)) { |
Pawel Zarembski |
0:01f31e923fe2 | 314 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 315 | return; |
Pawel Zarembski |
0:01f31e923fe2 | 316 | } |
Pawel Zarembski |
0:01f31e923fe2 | 317 | |
Pawel Zarembski |
0:01f31e923fe2 | 318 | fat->f[low_idx] = (val >> 0) & 0xFF; |
Pawel Zarembski |
0:01f31e923fe2 | 319 | fat->f[high_idx] = (val >> 8) & 0xFF; |
Pawel Zarembski |
0:01f31e923fe2 | 320 | } |
Pawel Zarembski |
0:01f31e923fe2 | 321 | |
Pawel Zarembski |
0:01f31e923fe2 | 322 | void vfs_init(const vfs_filename_t drive_name, uint32_t disk_size) |
Pawel Zarembski |
0:01f31e923fe2 | 323 | { |
Pawel Zarembski |
0:01f31e923fe2 | 324 | uint32_t i; |
Pawel Zarembski |
0:01f31e923fe2 | 325 | uint32_t num_clusters; |
Pawel Zarembski |
0:01f31e923fe2 | 326 | uint32_t total_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 327 | // Clear everything |
Pawel Zarembski |
0:01f31e923fe2 | 328 | memset(&mbr, 0, sizeof(mbr)); |
Pawel Zarembski |
0:01f31e923fe2 | 329 | memset(&fat, 0, sizeof(fat)); |
Pawel Zarembski |
0:01f31e923fe2 | 330 | fat_idx = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 331 | memset(&virtual_media, 0, sizeof(virtual_media)); |
Pawel Zarembski |
0:01f31e923fe2 | 332 | memset(&dir_current, 0, sizeof(dir_current)); |
Pawel Zarembski |
0:01f31e923fe2 | 333 | dir_idx = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 334 | file_count = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 335 | file_change_cb = file_change_cb_stub; |
Pawel Zarembski |
0:01f31e923fe2 | 336 | virtual_media_idx = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 337 | data_start = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 338 | // Initialize MBR |
Pawel Zarembski |
0:01f31e923fe2 | 339 | memcpy(&mbr, &mbr_tmpl, sizeof(mbr_t)); |
Pawel Zarembski |
0:01f31e923fe2 | 340 | total_sectors = ((disk_size + KB(64)) / mbr.bytes_per_sector); |
Pawel Zarembski |
0:01f31e923fe2 | 341 | // Make sure this is the right size for a FAT16 volume |
Pawel Zarembski |
0:01f31e923fe2 | 342 | if (total_sectors < FAT_CLUSTERS_MIN * mbr.sectors_per_cluster) { |
Pawel Zarembski |
0:01f31e923fe2 | 343 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 344 | total_sectors = FAT_CLUSTERS_MIN * mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 345 | } else if (total_sectors > FAT_CLUSTERS_MAX * mbr.sectors_per_cluster) { |
Pawel Zarembski |
0:01f31e923fe2 | 346 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 347 | total_sectors = FAT_CLUSTERS_MAX * mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 348 | } |
Pawel Zarembski |
0:01f31e923fe2 | 349 | if (total_sectors >= 0x10000) { |
Pawel Zarembski |
0:01f31e923fe2 | 350 | mbr.total_logical_sectors = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 351 | mbr.big_sectors_on_drive = total_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 352 | } else { |
Pawel Zarembski |
0:01f31e923fe2 | 353 | mbr.total_logical_sectors = total_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 354 | mbr.big_sectors_on_drive = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 355 | } |
Pawel Zarembski |
0:01f31e923fe2 | 356 | // FAT table will likely be larger than needed, but this is allowed by the |
Pawel Zarembski |
0:01f31e923fe2 | 357 | // fat specification |
Pawel Zarembski |
0:01f31e923fe2 | 358 | num_clusters = total_sectors / mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 359 | mbr.logical_sectors_per_fat = (num_clusters * 2 + VFS_SECTOR_SIZE - 1) / VFS_SECTOR_SIZE; |
Pawel Zarembski |
0:01f31e923fe2 | 360 | // Initailize virtual media |
Pawel Zarembski |
0:01f31e923fe2 | 361 | memcpy(&virtual_media, &virtual_media_tmpl, sizeof(virtual_media_tmpl)); |
Pawel Zarembski |
0:01f31e923fe2 | 362 | virtual_media[MEDIA_IDX_FAT1].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat; |
Pawel Zarembski |
0:01f31e923fe2 | 363 | virtual_media[MEDIA_IDX_FAT2].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat; |
Pawel Zarembski |
0:01f31e923fe2 | 364 | // Initialize indexes |
Pawel Zarembski |
0:01f31e923fe2 | 365 | virtual_media_idx = MEDIA_IDX_COUNT; |
Pawel Zarembski |
0:01f31e923fe2 | 366 | data_start = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 367 | |
Pawel Zarembski |
0:01f31e923fe2 | 368 | for (i = 0; i < ARRAY_SIZE(virtual_media_tmpl); i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 369 | data_start += virtual_media[i].length; |
Pawel Zarembski |
0:01f31e923fe2 | 370 | } |
Pawel Zarembski |
0:01f31e923fe2 | 371 | |
Pawel Zarembski |
0:01f31e923fe2 | 372 | // Initialize FAT |
Pawel Zarembski |
0:01f31e923fe2 | 373 | fat_idx = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 374 | write_fat(&fat, fat_idx, 0xFFF8); // Media type "media_descriptor" |
Pawel Zarembski |
0:01f31e923fe2 | 375 | fat_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 376 | write_fat(&fat, fat_idx, 0xFFFF); // FAT12 - always 0xFFF (no meaning), FAT16 - dirty/clean (clean = 0xFFFF) |
Pawel Zarembski |
0:01f31e923fe2 | 377 | fat_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 378 | // Initialize root dir |
Pawel Zarembski |
0:01f31e923fe2 | 379 | dir_idx = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 380 | dir_current.f[dir_idx] = root_dir_entry; |
Pawel Zarembski |
0:01f31e923fe2 | 381 | memcpy(dir_current.f[dir_idx].filename, drive_name, sizeof(dir_current.f[0].filename)); |
Pawel Zarembski |
0:01f31e923fe2 | 382 | dir_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 383 | } |
Pawel Zarembski |
0:01f31e923fe2 | 384 | |
Pawel Zarembski |
0:01f31e923fe2 | 385 | uint32_t vfs_get_total_size() |
Pawel Zarembski |
0:01f31e923fe2 | 386 | { |
Pawel Zarembski |
0:01f31e923fe2 | 387 | uint32_t size; |
Pawel Zarembski |
0:01f31e923fe2 | 388 | if (mbr.total_logical_sectors > 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 389 | size = mbr.total_logical_sectors * mbr.bytes_per_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 390 | } else if (mbr.big_sectors_on_drive > 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 391 | size = mbr.big_sectors_on_drive * mbr.bytes_per_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 392 | } else { |
Pawel Zarembski |
0:01f31e923fe2 | 393 | size = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 394 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 395 | } |
Pawel Zarembski |
0:01f31e923fe2 | 396 | return size; |
Pawel Zarembski |
0:01f31e923fe2 | 397 | } |
Pawel Zarembski |
0:01f31e923fe2 | 398 | |
Pawel Zarembski |
0:01f31e923fe2 | 399 | vfs_file_t vfs_create_file(const vfs_filename_t filename, vfs_read_cb_t read_cb, vfs_write_cb_t write_cb, uint32_t len) |
Pawel Zarembski |
0:01f31e923fe2 | 400 | { |
Pawel Zarembski |
0:01f31e923fe2 | 401 | uint32_t first_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 402 | FatDirectoryEntry_t *de; |
Pawel Zarembski |
0:01f31e923fe2 | 403 | uint32_t clusters; |
Pawel Zarembski |
0:01f31e923fe2 | 404 | uint32_t cluster_size; |
Pawel Zarembski |
0:01f31e923fe2 | 405 | uint32_t i; |
Pawel Zarembski |
0:01f31e923fe2 | 406 | util_assert(filename_valid(filename)); |
Pawel Zarembski |
0:01f31e923fe2 | 407 | // Compute the number of clusters in the file |
Pawel Zarembski |
0:01f31e923fe2 | 408 | cluster_size = mbr.bytes_per_sector * mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 409 | clusters = (len + cluster_size - 1) / cluster_size; |
Pawel Zarembski |
0:01f31e923fe2 | 410 | // Write the cluster chain to the fat table |
Pawel Zarembski |
0:01f31e923fe2 | 411 | first_cluster = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 412 | |
Pawel Zarembski |
0:01f31e923fe2 | 413 | if (len > 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 414 | first_cluster = fat_idx; |
Pawel Zarembski |
0:01f31e923fe2 | 415 | |
Pawel Zarembski |
0:01f31e923fe2 | 416 | for (i = 0; i < clusters - 1; i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 417 | write_fat(&fat, fat_idx, fat_idx + 1); |
Pawel Zarembski |
0:01f31e923fe2 | 418 | fat_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 419 | } |
Pawel Zarembski |
0:01f31e923fe2 | 420 | |
Pawel Zarembski |
0:01f31e923fe2 | 421 | write_fat(&fat, fat_idx, 0xFFFF); |
Pawel Zarembski |
0:01f31e923fe2 | 422 | fat_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 423 | } |
Pawel Zarembski |
0:01f31e923fe2 | 424 | |
Pawel Zarembski |
0:01f31e923fe2 | 425 | // Update directory entry |
Pawel Zarembski |
0:01f31e923fe2 | 426 | if (dir_idx >= ARRAY_SIZE(dir_current.f)) { |
Pawel Zarembski |
0:01f31e923fe2 | 427 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 428 | return VFS_FILE_INVALID; |
Pawel Zarembski |
0:01f31e923fe2 | 429 | } |
Pawel Zarembski |
0:01f31e923fe2 | 430 | |
Pawel Zarembski |
0:01f31e923fe2 | 431 | de = &dir_current.f[dir_idx]; |
Pawel Zarembski |
0:01f31e923fe2 | 432 | dir_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 433 | memcpy(de, &dir_entry_tmpl, sizeof(dir_entry_tmpl)); |
Pawel Zarembski |
0:01f31e923fe2 | 434 | memcpy(de->filename, filename, 11); |
Pawel Zarembski |
0:01f31e923fe2 | 435 | de->filesize = len; |
Pawel Zarembski |
0:01f31e923fe2 | 436 | de->first_cluster_high_16 = (first_cluster >> 16) & 0xFFFF; |
Pawel Zarembski |
0:01f31e923fe2 | 437 | de->first_cluster_low_16 = (first_cluster >> 0) & 0xFFFF; |
Pawel Zarembski |
0:01f31e923fe2 | 438 | |
Pawel Zarembski |
0:01f31e923fe2 | 439 | // Update virtual media |
Pawel Zarembski |
0:01f31e923fe2 | 440 | if (virtual_media_idx >= ARRAY_SIZE(virtual_media)) { |
Pawel Zarembski |
0:01f31e923fe2 | 441 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 442 | return VFS_FILE_INVALID; |
Pawel Zarembski |
0:01f31e923fe2 | 443 | } |
Pawel Zarembski |
0:01f31e923fe2 | 444 | |
Pawel Zarembski |
0:01f31e923fe2 | 445 | virtual_media[virtual_media_idx].read_cb = read_zero; |
Pawel Zarembski |
0:01f31e923fe2 | 446 | virtual_media[virtual_media_idx].write_cb = write_none; |
Pawel Zarembski |
0:01f31e923fe2 | 447 | |
Pawel Zarembski |
0:01f31e923fe2 | 448 | if (0 != read_cb) { |
Pawel Zarembski |
0:01f31e923fe2 | 449 | virtual_media[virtual_media_idx].read_cb = read_cb; |
Pawel Zarembski |
0:01f31e923fe2 | 450 | } |
Pawel Zarembski |
0:01f31e923fe2 | 451 | |
Pawel Zarembski |
0:01f31e923fe2 | 452 | if (0 != write_cb) { |
Pawel Zarembski |
0:01f31e923fe2 | 453 | virtual_media[virtual_media_idx].write_cb = write_cb; |
Pawel Zarembski |
0:01f31e923fe2 | 454 | } |
Pawel Zarembski |
0:01f31e923fe2 | 455 | |
Pawel Zarembski |
0:01f31e923fe2 | 456 | virtual_media[virtual_media_idx].length = clusters * mbr.bytes_per_sector * mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 457 | virtual_media_idx++; |
Pawel Zarembski |
0:01f31e923fe2 | 458 | file_count += 1; |
Pawel Zarembski |
0:01f31e923fe2 | 459 | return de; |
Pawel Zarembski |
0:01f31e923fe2 | 460 | } |
Pawel Zarembski |
0:01f31e923fe2 | 461 | |
Pawel Zarembski |
0:01f31e923fe2 | 462 | void vfs_file_set_attr(vfs_file_t file, vfs_file_attr_bit_t attr) |
Pawel Zarembski |
0:01f31e923fe2 | 463 | { |
Pawel Zarembski |
0:01f31e923fe2 | 464 | FatDirectoryEntry_t *de = file; |
Pawel Zarembski |
0:01f31e923fe2 | 465 | de->attributes = attr; |
Pawel Zarembski |
0:01f31e923fe2 | 466 | } |
Pawel Zarembski |
0:01f31e923fe2 | 467 | |
Pawel Zarembski |
0:01f31e923fe2 | 468 | vfs_sector_t vfs_file_get_start_sector(vfs_file_t file) |
Pawel Zarembski |
0:01f31e923fe2 | 469 | { |
Pawel Zarembski |
0:01f31e923fe2 | 470 | FatDirectoryEntry_t *de = file; |
Pawel Zarembski |
0:01f31e923fe2 | 471 | |
Pawel Zarembski |
0:01f31e923fe2 | 472 | if (vfs_file_get_size(file) == 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 473 | return VFS_INVALID_SECTOR; |
Pawel Zarembski |
0:01f31e923fe2 | 474 | } |
Pawel Zarembski |
0:01f31e923fe2 | 475 | |
Pawel Zarembski |
0:01f31e923fe2 | 476 | return cluster_to_sector(de->first_cluster_low_16); |
Pawel Zarembski |
0:01f31e923fe2 | 477 | } |
Pawel Zarembski |
0:01f31e923fe2 | 478 | |
Pawel Zarembski |
0:01f31e923fe2 | 479 | uint32_t vfs_file_get_size(vfs_file_t file) |
Pawel Zarembski |
0:01f31e923fe2 | 480 | { |
Pawel Zarembski |
0:01f31e923fe2 | 481 | FatDirectoryEntry_t *de = file; |
Pawel Zarembski |
0:01f31e923fe2 | 482 | return de->filesize; |
Pawel Zarembski |
0:01f31e923fe2 | 483 | } |
Pawel Zarembski |
0:01f31e923fe2 | 484 | |
Pawel Zarembski |
0:01f31e923fe2 | 485 | vfs_file_attr_bit_t vfs_file_get_attr(vfs_file_t file) |
Pawel Zarembski |
0:01f31e923fe2 | 486 | { |
Pawel Zarembski |
0:01f31e923fe2 | 487 | FatDirectoryEntry_t *de = file; |
Pawel Zarembski |
0:01f31e923fe2 | 488 | return (vfs_file_attr_bit_t)de->attributes; |
Pawel Zarembski |
0:01f31e923fe2 | 489 | } |
Pawel Zarembski |
0:01f31e923fe2 | 490 | |
Pawel Zarembski |
0:01f31e923fe2 | 491 | void vfs_set_file_change_callback(vfs_file_change_cb_t cb) |
Pawel Zarembski |
0:01f31e923fe2 | 492 | { |
Pawel Zarembski |
0:01f31e923fe2 | 493 | file_change_cb = cb; |
Pawel Zarembski |
0:01f31e923fe2 | 494 | } |
Pawel Zarembski |
0:01f31e923fe2 | 495 | |
Pawel Zarembski |
0:01f31e923fe2 | 496 | void vfs_read(uint32_t requested_sector, uint8_t *buf, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 497 | { |
Pawel Zarembski |
0:01f31e923fe2 | 498 | uint8_t i = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 499 | uint32_t current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 500 | // Zero out the buffer |
Pawel Zarembski |
0:01f31e923fe2 | 501 | memset(buf, 0, num_sectors * VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 502 | current_sector = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 503 | |
Pawel Zarembski |
0:01f31e923fe2 | 504 | for (i = 0; i < ARRAY_SIZE(virtual_media); i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 505 | uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE; |
Pawel Zarembski |
0:01f31e923fe2 | 506 | uint32_t vm_start = current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 507 | uint32_t vm_end = current_sector + vm_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 508 | |
Pawel Zarembski |
0:01f31e923fe2 | 509 | // Data can be used in this sector |
Pawel Zarembski |
0:01f31e923fe2 | 510 | if ((requested_sector >= vm_start) && (requested_sector < vm_end)) { |
Pawel Zarembski |
0:01f31e923fe2 | 511 | uint32_t sector_offset; |
Pawel Zarembski |
0:01f31e923fe2 | 512 | uint32_t sectors_to_write = vm_end - requested_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 513 | sectors_to_write = MIN(sectors_to_write, num_sectors); |
Pawel Zarembski |
0:01f31e923fe2 | 514 | sector_offset = requested_sector - current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 515 | virtual_media[i].read_cb(sector_offset, buf, sectors_to_write); |
Pawel Zarembski |
0:01f31e923fe2 | 516 | // Update requested sector |
Pawel Zarembski |
0:01f31e923fe2 | 517 | requested_sector += sectors_to_write; |
Pawel Zarembski |
0:01f31e923fe2 | 518 | num_sectors -= sectors_to_write; |
Pawel Zarembski |
0:01f31e923fe2 | 519 | } |
Pawel Zarembski |
0:01f31e923fe2 | 520 | |
Pawel Zarembski |
0:01f31e923fe2 | 521 | // If there is no more data to be read then break |
Pawel Zarembski |
0:01f31e923fe2 | 522 | if (num_sectors == 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 523 | break; |
Pawel Zarembski |
0:01f31e923fe2 | 524 | } |
Pawel Zarembski |
0:01f31e923fe2 | 525 | |
Pawel Zarembski |
0:01f31e923fe2 | 526 | // Move to the next virtual media entry |
Pawel Zarembski |
0:01f31e923fe2 | 527 | current_sector += vm_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 528 | } |
Pawel Zarembski |
0:01f31e923fe2 | 529 | } |
Pawel Zarembski |
0:01f31e923fe2 | 530 | |
Pawel Zarembski |
0:01f31e923fe2 | 531 | void vfs_write(uint32_t requested_sector, const uint8_t *buf, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 532 | { |
Pawel Zarembski |
0:01f31e923fe2 | 533 | uint8_t i = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 534 | uint32_t current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 535 | current_sector = 0; |
Pawel Zarembski |
0:01f31e923fe2 | 536 | |
Pawel Zarembski |
0:01f31e923fe2 | 537 | for (i = 0; i < virtual_media_idx; i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 538 | uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE; |
Pawel Zarembski |
0:01f31e923fe2 | 539 | uint32_t vm_start = current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 540 | uint32_t vm_end = current_sector + vm_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 541 | |
Pawel Zarembski |
0:01f31e923fe2 | 542 | // Data can be used in this sector |
Pawel Zarembski |
0:01f31e923fe2 | 543 | if ((requested_sector >= vm_start) && (requested_sector < vm_end)) { |
Pawel Zarembski |
0:01f31e923fe2 | 544 | uint32_t sector_offset; |
Pawel Zarembski |
0:01f31e923fe2 | 545 | uint32_t sectors_to_read = vm_end - requested_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 546 | sectors_to_read = MIN(sectors_to_read, num_sectors); |
Pawel Zarembski |
0:01f31e923fe2 | 547 | sector_offset = requested_sector - current_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 548 | virtual_media[i].write_cb(sector_offset, buf, sectors_to_read); |
Pawel Zarembski |
0:01f31e923fe2 | 549 | // Update requested sector |
Pawel Zarembski |
0:01f31e923fe2 | 550 | requested_sector += sectors_to_read; |
Pawel Zarembski |
0:01f31e923fe2 | 551 | num_sectors -= sectors_to_read; |
Pawel Zarembski |
0:01f31e923fe2 | 552 | } |
Pawel Zarembski |
0:01f31e923fe2 | 553 | |
Pawel Zarembski |
0:01f31e923fe2 | 554 | // If there is no more data to be read then break |
Pawel Zarembski |
0:01f31e923fe2 | 555 | if (num_sectors == 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 556 | break; |
Pawel Zarembski |
0:01f31e923fe2 | 557 | } |
Pawel Zarembski |
0:01f31e923fe2 | 558 | |
Pawel Zarembski |
0:01f31e923fe2 | 559 | // Move to the next virtual media entry |
Pawel Zarembski |
0:01f31e923fe2 | 560 | current_sector += vm_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 561 | } |
Pawel Zarembski |
0:01f31e923fe2 | 562 | } |
Pawel Zarembski |
0:01f31e923fe2 | 563 | |
Pawel Zarembski |
0:01f31e923fe2 | 564 | static uint32_t read_zero(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 565 | { |
Pawel Zarembski |
0:01f31e923fe2 | 566 | uint32_t read_size = VFS_SECTOR_SIZE * num_sectors; |
Pawel Zarembski |
0:01f31e923fe2 | 567 | memset(data, 0, read_size); |
Pawel Zarembski |
0:01f31e923fe2 | 568 | return read_size; |
Pawel Zarembski |
0:01f31e923fe2 | 569 | } |
Pawel Zarembski |
0:01f31e923fe2 | 570 | |
Pawel Zarembski |
0:01f31e923fe2 | 571 | static void write_none(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 572 | { |
Pawel Zarembski |
0:01f31e923fe2 | 573 | // Do nothing |
Pawel Zarembski |
0:01f31e923fe2 | 574 | } |
Pawel Zarembski |
0:01f31e923fe2 | 575 | |
Pawel Zarembski |
0:01f31e923fe2 | 576 | static uint32_t read_mbr(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 577 | { |
Pawel Zarembski |
0:01f31e923fe2 | 578 | uint32_t read_size = sizeof(mbr_t); |
Pawel Zarembski |
0:01f31e923fe2 | 579 | COMPILER_ASSERT(sizeof(mbr_t) <= VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 580 | |
Pawel Zarembski |
0:01f31e923fe2 | 581 | if (sector_offset != 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 582 | // Don't worry about reading other sectors |
Pawel Zarembski |
0:01f31e923fe2 | 583 | return 0; |
Pawel Zarembski |
0:01f31e923fe2 | 584 | } |
Pawel Zarembski |
0:01f31e923fe2 | 585 | |
Pawel Zarembski |
0:01f31e923fe2 | 586 | memcpy(data, &mbr, read_size); |
Pawel Zarembski |
0:01f31e923fe2 | 587 | return read_size; |
Pawel Zarembski |
0:01f31e923fe2 | 588 | } |
Pawel Zarembski |
0:01f31e923fe2 | 589 | |
Pawel Zarembski |
0:01f31e923fe2 | 590 | /* No need to handle writes to the mbr */ |
Pawel Zarembski |
0:01f31e923fe2 | 591 | |
Pawel Zarembski |
0:01f31e923fe2 | 592 | static uint32_t read_fat(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 593 | { |
Pawel Zarembski |
0:01f31e923fe2 | 594 | uint32_t read_size = sizeof(file_allocation_table_t); |
Pawel Zarembski |
0:01f31e923fe2 | 595 | COMPILER_ASSERT(sizeof(file_allocation_table_t) <= VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 596 | |
Pawel Zarembski |
0:01f31e923fe2 | 597 | if (sector_offset != 0) { |
Pawel Zarembski |
0:01f31e923fe2 | 598 | // Don't worry about reading other sectors |
Pawel Zarembski |
0:01f31e923fe2 | 599 | return 0; |
Pawel Zarembski |
0:01f31e923fe2 | 600 | } |
Pawel Zarembski |
0:01f31e923fe2 | 601 | |
Pawel Zarembski |
0:01f31e923fe2 | 602 | memcpy(data, &fat, read_size); |
Pawel Zarembski |
0:01f31e923fe2 | 603 | return read_size; |
Pawel Zarembski |
0:01f31e923fe2 | 604 | } |
Pawel Zarembski |
0:01f31e923fe2 | 605 | |
Pawel Zarembski |
0:01f31e923fe2 | 606 | /* No need to handle writes to the fat */ |
Pawel Zarembski |
0:01f31e923fe2 | 607 | |
Pawel Zarembski |
0:01f31e923fe2 | 608 | static uint32_t read_dir(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 609 | { |
Pawel Zarembski |
0:01f31e923fe2 | 610 | if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) { |
Pawel Zarembski |
0:01f31e923fe2 | 611 | // Trying to read too much of the root directory |
Pawel Zarembski |
0:01f31e923fe2 | 612 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 613 | return 0; |
Pawel Zarembski |
0:01f31e923fe2 | 614 | } |
Pawel Zarembski |
0:01f31e923fe2 | 615 | |
Pawel Zarembski |
0:01f31e923fe2 | 616 | // Zero buffer data is VFS_SECTOR_SIZE max |
Pawel Zarembski |
0:01f31e923fe2 | 617 | memset(data, 0, VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 618 | |
Pawel Zarembski |
0:01f31e923fe2 | 619 | if (sector_offset == 0) { //Handle the first 512 bytes |
Pawel Zarembski |
0:01f31e923fe2 | 620 | // Copy data that is actually created in the directory |
Pawel Zarembski |
0:01f31e923fe2 | 621 | memcpy(data, &dir_current.f[0], dir_idx*sizeof(FatDirectoryEntry_t)); |
Pawel Zarembski |
0:01f31e923fe2 | 622 | } |
Pawel Zarembski |
0:01f31e923fe2 | 623 | |
Pawel Zarembski |
0:01f31e923fe2 | 624 | return num_sectors * VFS_SECTOR_SIZE; |
Pawel Zarembski |
0:01f31e923fe2 | 625 | } |
Pawel Zarembski |
0:01f31e923fe2 | 626 | |
Pawel Zarembski |
0:01f31e923fe2 | 627 | static void write_dir(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors) |
Pawel Zarembski |
0:01f31e923fe2 | 628 | { |
Pawel Zarembski |
0:01f31e923fe2 | 629 | FatDirectoryEntry_t *old_entry; |
Pawel Zarembski |
0:01f31e923fe2 | 630 | FatDirectoryEntry_t *new_entry; |
Pawel Zarembski |
0:01f31e923fe2 | 631 | uint32_t start_index; |
Pawel Zarembski |
0:01f31e923fe2 | 632 | uint32_t num_entries; |
Pawel Zarembski |
0:01f31e923fe2 | 633 | uint32_t i; |
Pawel Zarembski |
0:01f31e923fe2 | 634 | |
Pawel Zarembski |
0:01f31e923fe2 | 635 | if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) { |
Pawel Zarembski |
0:01f31e923fe2 | 636 | // Trying to write too much of the root directory |
Pawel Zarembski |
0:01f31e923fe2 | 637 | util_assert(0); |
Pawel Zarembski |
0:01f31e923fe2 | 638 | return; |
Pawel Zarembski |
0:01f31e923fe2 | 639 | } |
Pawel Zarembski |
0:01f31e923fe2 | 640 | |
Pawel Zarembski |
0:01f31e923fe2 | 641 | start_index = sector_offset * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t); |
Pawel Zarembski |
0:01f31e923fe2 | 642 | num_entries = num_sectors * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t); |
Pawel Zarembski |
0:01f31e923fe2 | 643 | old_entry = &dir_current.f[start_index]; |
Pawel Zarembski |
0:01f31e923fe2 | 644 | new_entry = (FatDirectoryEntry_t *)data; |
Pawel Zarembski |
0:01f31e923fe2 | 645 | // If this is the first sector start at index 1 to get past drive name |
Pawel Zarembski |
0:01f31e923fe2 | 646 | i = 0 == sector_offset ? 1 : 0; |
Pawel Zarembski |
0:01f31e923fe2 | 647 | |
Pawel Zarembski |
0:01f31e923fe2 | 648 | for (; i < num_entries; i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 649 | bool same_name; |
Pawel Zarembski |
0:01f31e923fe2 | 650 | |
Pawel Zarembski |
0:01f31e923fe2 | 651 | if (0 == memcmp(&old_entry[i], &new_entry[i], sizeof(FatDirectoryEntry_t))) { |
Pawel Zarembski |
0:01f31e923fe2 | 652 | continue; |
Pawel Zarembski |
0:01f31e923fe2 | 653 | } |
Pawel Zarembski |
0:01f31e923fe2 | 654 | |
Pawel Zarembski |
0:01f31e923fe2 | 655 | // If were at this point then something has changed in the file |
Pawel Zarembski |
0:01f31e923fe2 | 656 | same_name = (0 == memcmp(old_entry[i].filename, new_entry[i].filename, sizeof(new_entry[i].filename))) ? 1 : 0; |
Pawel Zarembski |
0:01f31e923fe2 | 657 | // Changed |
Pawel Zarembski |
0:01f31e923fe2 | 658 | file_change_cb(new_entry[i].filename, VFS_FILE_CHANGED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); |
Pawel Zarembski |
0:01f31e923fe2 | 659 | |
Pawel Zarembski |
0:01f31e923fe2 | 660 | // Deleted |
Pawel Zarembski |
0:01f31e923fe2 | 661 | if (0xe5 == (uint8_t)new_entry[i].filename[0]) { |
Pawel Zarembski |
0:01f31e923fe2 | 662 | file_change_cb(old_entry[i].filename, VFS_FILE_DELETED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); |
Pawel Zarembski |
0:01f31e923fe2 | 663 | continue; |
Pawel Zarembski |
0:01f31e923fe2 | 664 | } |
Pawel Zarembski |
0:01f31e923fe2 | 665 | |
Pawel Zarembski |
0:01f31e923fe2 | 666 | // Created |
Pawel Zarembski |
0:01f31e923fe2 | 667 | if (!same_name && filename_valid(new_entry[i].filename)) { |
Pawel Zarembski |
0:01f31e923fe2 | 668 | file_change_cb(new_entry[i].filename, VFS_FILE_CREATED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); |
Pawel Zarembski |
0:01f31e923fe2 | 669 | continue; |
Pawel Zarembski |
0:01f31e923fe2 | 670 | } |
Pawel Zarembski |
0:01f31e923fe2 | 671 | } |
Pawel Zarembski |
0:01f31e923fe2 | 672 | |
Pawel Zarembski |
0:01f31e923fe2 | 673 | memcpy(&dir_current.f[start_index], data, num_sectors * VFS_SECTOR_SIZE); |
Pawel Zarembski |
0:01f31e923fe2 | 674 | } |
Pawel Zarembski |
0:01f31e923fe2 | 675 | |
Pawel Zarembski |
0:01f31e923fe2 | 676 | static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data) |
Pawel Zarembski |
0:01f31e923fe2 | 677 | { |
Pawel Zarembski |
0:01f31e923fe2 | 678 | // Do nothing |
Pawel Zarembski |
0:01f31e923fe2 | 679 | } |
Pawel Zarembski |
0:01f31e923fe2 | 680 | |
Pawel Zarembski |
0:01f31e923fe2 | 681 | static uint32_t cluster_to_sector(uint32_t cluster_idx) |
Pawel Zarembski |
0:01f31e923fe2 | 682 | { |
Pawel Zarembski |
0:01f31e923fe2 | 683 | uint32_t sectors_before_data = data_start / mbr.bytes_per_sector; |
Pawel Zarembski |
0:01f31e923fe2 | 684 | return sectors_before_data + (cluster_idx - 2) * mbr.sectors_per_cluster; |
Pawel Zarembski |
0:01f31e923fe2 | 685 | } |
Pawel Zarembski |
0:01f31e923fe2 | 686 | |
Pawel Zarembski |
0:01f31e923fe2 | 687 | static bool filename_valid(const vfs_filename_t filename) |
Pawel Zarembski |
0:01f31e923fe2 | 688 | { |
Pawel Zarembski |
0:01f31e923fe2 | 689 | // Information on valid 8.3 filenames can be found in |
Pawel Zarembski |
0:01f31e923fe2 | 690 | // the microsoft hardware whitepaper: |
Pawel Zarembski |
0:01f31e923fe2 | 691 | // |
Pawel Zarembski |
0:01f31e923fe2 | 692 | // Microsoft Extensible Firmware Initiative |
Pawel Zarembski |
0:01f31e923fe2 | 693 | // FAT32 File System Specification |
Pawel Zarembski |
0:01f31e923fe2 | 694 | // FAT: General Overview of On-Disk Format |
Pawel Zarembski |
0:01f31e923fe2 | 695 | const char invalid_starting_chars[] = { |
Pawel Zarembski |
0:01f31e923fe2 | 696 | 0xE5, // Deleted |
Pawel Zarembski |
0:01f31e923fe2 | 697 | 0x00, // Deleted (and all following entries are free) |
Pawel Zarembski |
0:01f31e923fe2 | 698 | 0x20, // Space not allowed as first character |
Pawel Zarembski |
0:01f31e923fe2 | 699 | }; |
Pawel Zarembski |
0:01f31e923fe2 | 700 | uint32_t i; |
Pawel Zarembski |
0:01f31e923fe2 | 701 | |
Pawel Zarembski |
0:01f31e923fe2 | 702 | // Check for invalid starting characters |
Pawel Zarembski |
0:01f31e923fe2 | 703 | for (i = 0; i < sizeof(invalid_starting_chars); i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 704 | if (invalid_starting_chars[i] == filename[0]) { |
Pawel Zarembski |
0:01f31e923fe2 | 705 | return false; |
Pawel Zarembski |
0:01f31e923fe2 | 706 | } |
Pawel Zarembski |
0:01f31e923fe2 | 707 | } |
Pawel Zarembski |
0:01f31e923fe2 | 708 | |
Pawel Zarembski |
0:01f31e923fe2 | 709 | // Make sure all the characters are valid |
Pawel Zarembski |
0:01f31e923fe2 | 710 | for (i = 0; i < sizeof(vfs_filename_t); i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 711 | if (!filename_character_valid(filename[i])) { |
Pawel Zarembski |
0:01f31e923fe2 | 712 | return false; |
Pawel Zarembski |
0:01f31e923fe2 | 713 | } |
Pawel Zarembski |
0:01f31e923fe2 | 714 | } |
Pawel Zarembski |
0:01f31e923fe2 | 715 | |
Pawel Zarembski |
0:01f31e923fe2 | 716 | // All checks have passed so filename is valid |
Pawel Zarembski |
0:01f31e923fe2 | 717 | return true; |
Pawel Zarembski |
0:01f31e923fe2 | 718 | } |
Pawel Zarembski |
0:01f31e923fe2 | 719 | |
Pawel Zarembski |
0:01f31e923fe2 | 720 | static bool filename_character_valid(char character) |
Pawel Zarembski |
0:01f31e923fe2 | 721 | { |
Pawel Zarembski |
0:01f31e923fe2 | 722 | const char invalid_chars[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C}; |
Pawel Zarembski |
0:01f31e923fe2 | 723 | uint32_t i; |
Pawel Zarembski |
0:01f31e923fe2 | 724 | |
Pawel Zarembski |
0:01f31e923fe2 | 725 | // Lower case characters are not allowed |
Pawel Zarembski |
0:01f31e923fe2 | 726 | if ((character >= 'a') && (character <= 'z')) { |
Pawel Zarembski |
0:01f31e923fe2 | 727 | return false; |
Pawel Zarembski |
0:01f31e923fe2 | 728 | } |
Pawel Zarembski |
0:01f31e923fe2 | 729 | |
Pawel Zarembski |
0:01f31e923fe2 | 730 | // Values less than 0x20 are not allowed except 0x5 |
Pawel Zarembski |
0:01f31e923fe2 | 731 | if ((character < 0x20) && (character != 0x5)) { |
Pawel Zarembski |
0:01f31e923fe2 | 732 | return false; |
Pawel Zarembski |
0:01f31e923fe2 | 733 | } |
Pawel Zarembski |
0:01f31e923fe2 | 734 | |
Pawel Zarembski |
0:01f31e923fe2 | 735 | // Check for special characters that are not allowed |
Pawel Zarembski |
0:01f31e923fe2 | 736 | for (i = 0; i < sizeof(invalid_chars); i++) { |
Pawel Zarembski |
0:01f31e923fe2 | 737 | if (invalid_chars[i] == character) { |
Pawel Zarembski |
0:01f31e923fe2 | 738 | return false; |
Pawel Zarembski |
0:01f31e923fe2 | 739 | } |
Pawel Zarembski |
0:01f31e923fe2 | 740 | } |
Pawel Zarembski |
0:01f31e923fe2 | 741 | |
Pawel Zarembski |
0:01f31e923fe2 | 742 | // All of the checks have passed so this is a valid file name character |
Pawel Zarembski |
0:01f31e923fe2 | 743 | return true; |
Pawel Zarembski |
0:01f31e923fe2 | 744 | } |