Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
virtual_fs.c
00001 /** 00002 * @file virtual_fs.c 00003 * @brief Implementation of virtual_fs.h 00004 * 00005 * DAPLink Interface Firmware 00006 * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved 00007 * SPDX-License-Identifier: Apache-2.0 00008 * 00009 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00010 * not use this file except in compliance with the License. 00011 * You may obtain a copy of the License at 00012 * 00013 * http://www.apache.org/licenses/LICENSE-2.0 00014 * 00015 * Unless required by applicable law or agreed to in writing, software 00016 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00017 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00018 * See the License for the specific language governing permissions and 00019 * limitations under the License. 00020 */ 00021 00022 #include <string.h> 00023 00024 #include "virtual_fs.h" 00025 #include "info.h" 00026 #include "settings.h" 00027 #include "compiler.h" 00028 #include "util.h" 00029 00030 // Virtual file system driver 00031 // Limitations: 00032 // - files must be contiguous 00033 // - data written cannot be read back 00034 // - data should only be read once 00035 00036 // FAT16 limitations +- safety margin 00037 #define FAT_CLUSTERS_MAX (65525 - 100) 00038 #define FAT_CLUSTERS_MIN (4086 + 100) 00039 00040 typedef struct { 00041 uint8_t boot_sector[11]; 00042 /* DOS 2.0 BPB - Bios Parameter Block, 11 bytes */ 00043 uint16_t bytes_per_sector; 00044 uint8_t sectors_per_cluster; 00045 uint16_t reserved_logical_sectors; 00046 uint8_t num_fats; 00047 uint16_t max_root_dir_entries; 00048 uint16_t total_logical_sectors; 00049 uint8_t media_descriptor; 00050 uint16_t logical_sectors_per_fat; 00051 /* DOS 3.31 BPB - Bios Parameter Block, 12 bytes */ 00052 uint16_t physical_sectors_per_track; 00053 uint16_t heads; 00054 uint32_t hidden_sectors; 00055 uint32_t big_sectors_on_drive; 00056 /* Extended BIOS Parameter Block, 26 bytes */ 00057 uint8_t physical_drive_number; 00058 uint8_t not_used; 00059 uint8_t boot_record_signature; 00060 uint32_t volume_id; 00061 char volume_label[11]; 00062 char file_system_type[8]; 00063 /* bootstrap data in bytes 62-509 */ 00064 uint8_t bootstrap[448]; 00065 /* These entries in place of bootstrap code are the *nix partitions */ 00066 //uint8_t partition_one[16]; 00067 //uint8_t partition_two[16]; 00068 //uint8_t partition_three[16]; 00069 //uint8_t partition_four[16]; 00070 /* Mandatory value at bytes 510-511, must be 0xaa55 */ 00071 uint16_t signature; 00072 } __attribute__((packed)) mbr_t; 00073 00074 typedef struct file_allocation_table { 00075 uint8_t f[512]; 00076 } file_allocation_table_t; 00077 00078 typedef struct FatDirectoryEntry { 00079 vfs_filename_t filename; 00080 uint8_t attributes; 00081 uint8_t reserved; 00082 uint8_t creation_time_ms; 00083 uint16_t creation_time; 00084 uint16_t creation_date; 00085 uint16_t accessed_date; 00086 uint16_t first_cluster_high_16; 00087 uint16_t modification_time; 00088 uint16_t modification_date; 00089 uint16_t first_cluster_low_16; 00090 uint32_t filesize; 00091 } __attribute__((packed)) FatDirectoryEntry_t; 00092 COMPILER_ASSERT(sizeof(FatDirectoryEntry_t) == 32); 00093 00094 // to save RAM all files must be in the first root dir entry (512 bytes) 00095 // but 2 actually exist on disc (32 entries) to accomodate hidden OS files, 00096 // folders and metadata 00097 typedef struct root_dir { 00098 FatDirectoryEntry_t f[32]; 00099 } root_dir_t; 00100 00101 typedef struct virtual_media { 00102 vfs_read_cb_t read_cb; 00103 vfs_write_cb_t write_cb; 00104 uint32_t length; 00105 } virtual_media_t; 00106 00107 static uint32_t read_zero(uint32_t offset, uint8_t *data, uint32_t size); 00108 static void write_none(uint32_t offset, const uint8_t *data, uint32_t size); 00109 00110 static uint32_t read_mbr(uint32_t offset, uint8_t *data, uint32_t size); 00111 static uint32_t read_fat(uint32_t offset, uint8_t *data, uint32_t size); 00112 static uint32_t read_dir(uint32_t offset, uint8_t *data, uint32_t size); 00113 static void write_dir(uint32_t offset, const uint8_t *data, uint32_t size); 00114 static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change, 00115 vfs_file_t file, vfs_file_t new_file_data); 00116 static uint32_t cluster_to_sector(uint32_t cluster_idx); 00117 static bool filename_valid(const vfs_filename_t filename); 00118 static bool filename_character_valid(char character); 00119 00120 // If sector size changes update comment below 00121 COMPILER_ASSERT(0x0200 == VFS_SECTOR_SIZE); 00122 // If root directory size changes update max_root_dir_entries 00123 COMPILER_ASSERT(0x0020 == sizeof(root_dir_t) / sizeof(FatDirectoryEntry_t)); 00124 static const mbr_t mbr_tmpl = { 00125 /*uint8_t[11]*/.boot_sector = { 00126 0xEB, 0x3C, 0x90, 00127 'M', 'S', 'D', '0', 'S', '4', '.', '1' // OEM Name in text (8 chars max) 00128 }, 00129 /*uint16_t*/.bytes_per_sector = 0x0200, // 512 bytes per sector 00130 /*uint8_t */.sectors_per_cluster = 0x08, // 4k cluser 00131 /*uint16_t*/.reserved_logical_sectors = 0x0001, // mbr is 1 sector 00132 /*uint8_t */.num_fats = 0x02, // 2 FATs 00133 /*uint16_t*/.max_root_dir_entries = 0x0020, // 32 dir entries (max) 00134 /*uint16_t*/.total_logical_sectors = 0x1f50, // sector size * # of sectors = drive size 00135 /*uint8_t */.media_descriptor = 0xf8, // fixed disc = F8, removable = F0 00136 /*uint16_t*/.logical_sectors_per_fat = 0x0001, // FAT is 1k - ToDO:need to edit this 00137 /*uint16_t*/.physical_sectors_per_track = 0x0001, // flat 00138 /*uint16_t*/.heads = 0x0001, // flat 00139 /*uint32_t*/.hidden_sectors = 0x00000000, // before mbt, 0 00140 /*uint32_t*/.big_sectors_on_drive = 0x00000000, // 4k sector. not using large clusters 00141 /*uint8_t */.physical_drive_number = 0x00, 00142 /*uint8_t */.not_used = 0x00, // Current head. Linux tries to set this to 0x1 00143 /*uint8_t */.boot_record_signature = 0x29, // signature is present 00144 /*uint32_t*/.volume_id = 0x27021974, // serial number 00145 // needs to match the root dir label 00146 /*char[11]*/.volume_label = {'D', 'A', 'P', 'L', 'I', 'N', 'K', '-', 'D', 'N', 'D'}, 00147 // unused by msft - just a label (FAT, FAT12, FAT16) 00148 /*char[8] */.file_system_type = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}, 00149 00150 /* BOOTSTRAP SOURCE CODE AND PAYLOAD GENERATOR 00151 * PRINTS OUT WARNING MESSAGE ON ACCIDENTAL BOOT FROM DAPLINK 00152 1 [BITS 16] 00153 2 %define BLSTART 0x3E 00154 3 %define BLLEN 448 00155 4 00156 5 00000000 FA cli 00157 6 00000001 B8C007 mov ax, 07C0h 00158 7 00000004 052001 add ax, 288 00159 8 00000007 8ED0 mov ss, ax 00160 9 00000009 BC0010 mov sp, 4096 00161 10 0000000C B8C007 mov ax, 07C0h 00162 11 0000000F 8ED8 mov ds, ax 00163 12 00000011 BE[6D00] mov si,message+BLSTART 00164 13 00000014 E80B00 call print 00165 14 00000017 EBFE jmp $ 00166 15 00167 16 printc: 00168 17 00000019 B40E mov ah, 0x0E 00169 18 0000001B B700 mov bh, 0x00 00170 19 0000001D B307 mov bl, 0x07 00171 20 0000001F CD10 int 0x10 00172 21 00000021 C3 ret 00173 22 00174 23 print: 00175 24 nextc: 00176 25 00000022 8A04 mov al, [si] 00177 26 00000024 46 inc si 00178 27 00000025 08C0 or al, al 00179 28 00000027 7405 jz return 00180 29 00000029 E8EDFF call printc 00181 30 0000002C EBF4 jmp nextc 00182 31 return: 00183 32 0000002E C3 ret 00184 33 00185 34 0000002F 504C45415345205245- message db 'PLEASE REMOVE THE ARM MBED DAPLINK USB DEVICE AND REBOOT THE SYSTEM..', 0 00186 35 00000038 4D4F56452054484520- 00187 36 00000041 41524D204D42454420- 00188 37 0000004A 4441504C494E4B2055- 00189 38 00000053 534220444556494345- 00190 39 0000005C 20414E44205245424F- 00191 40 00000065 4F5420544845205359- 00192 41 0000006E 5354454D2E2E00 00193 42 00194 43 00000075 00<rept> times BLLEN-($-$$) db 0 00195 00196 USE BELOW SCRIPT TO COMPILE BOOTSTRAP AND GENERATE PAYLOAD: 00197 #!/usr/bin/env python 00198 import os 00199 os.system('nasm -f bin -o print.bin -l print.lst print.asm') 00200 print(open('print.lst','r').read()) 00201 x=1 00202 for c in open('print.bin','rb').read(): 00203 print('0x%02X, '%c, end='' if x % 16 else '\n') 00204 x += 1 00205 */ 00206 /*uint8_t[448]*/.bootstrap = { 00207 0xFA, 0xB8, 0xC0, 0x07, 0x05, 0x20, 0x01, 0x8E, 0xD0, 0xBC, 0x00, 0x10, 0xB8, 0xC0, 0x07, 0x8E, 00208 0xD8, 0xBE, 0x6D, 0x00, 0xE8, 0x0B, 0x00, 0xEB, 0xFE, 0xB4, 0x0E, 0xB7, 0x00, 0xB3, 0x07, 0xCD, 00209 0x10, 0xC3, 0x8A, 0x04, 0x46, 0x08, 0xC0, 0x74, 0x05, 0xE8, 0xED, 0xFF, 0xEB, 0xF4, 0xC3, 0x50, 00210 0x4C, 0x45, 0x41, 0x53, 0x45, 0x20, 0x52, 0x45, 0x4D, 0x4F, 0x56, 0x45, 0x20, 0x54, 0x48, 0x45, 00211 0x20, 0x41, 0x52, 0x4D, 0x20, 0x4D, 0x42, 0x45, 0x44, 0x20, 0x44, 0x41, 0x50, 0x4C, 0x49, 0x4E, 00212 0x4B, 0x20, 0x55, 0x53, 0x42, 0x20, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x20, 0x41, 0x4E, 0x44, 00213 0x20, 0x52, 0x45, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x59, 0x53, 0x54, 00214 0x45, 0x4D, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00235 }, 00236 // Signature MUST be 0xAA55 to maintain compatibility (i.e. with Android). 00237 /*uint16_t*/.signature = 0xAA55, 00238 }; 00239 00240 enum virtual_media_idx_t { 00241 MEDIA_IDX_MBR = 0, 00242 MEDIA_IDX_FAT1, 00243 MEDIA_IDX_FAT2, 00244 MEDIA_IDX_ROOT_DIR, 00245 00246 MEDIA_IDX_COUNT 00247 }; 00248 00249 // Note - everything in virtual media must be a multiple of VFS_SECTOR_SIZE 00250 const virtual_media_t virtual_media_tmpl[] = { 00251 /* Read CB Write CB Region Size Region Name */ 00252 { read_mbr, write_none, VFS_SECTOR_SIZE }, /* MBR */ 00253 { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT1 */ 00254 { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT2 */ 00255 { read_dir, write_dir, VFS_SECTOR_SIZE * 2 }, /* Root Dir */ 00256 /* Raw filesystem contents follow */ 00257 }; 00258 // Keep virtual_media_idx_t in sync with virtual_media_tmpl 00259 COMPILER_ASSERT(MEDIA_IDX_COUNT == ARRAY_SIZE(virtual_media_tmpl)); 00260 00261 static const FatDirectoryEntry_t root_dir_entry = { 00262 /*uint8_t[11] */ .filename = {""}, 00263 /*uint8_t */ .attributes = VFS_FILE_ATTR_VOLUME_LABEL | VFS_FILE_ATTR_ARCHIVE, 00264 /*uint8_t */ .reserved = 0x00, 00265 /*uint8_t */ .creation_time_ms = 0x00, 00266 /*uint16_t*/ .creation_time = 0x0000, 00267 /*uint16_t*/ .creation_date = 0x0000, 00268 /*uint16_t*/ .accessed_date = 0x0000, 00269 /*uint16_t*/ .first_cluster_high_16 = 0x0000, 00270 /*uint16_t*/ .modification_time = 0x8E41, 00271 /*uint16_t*/ .modification_date = 0x32bb, 00272 /*uint16_t*/ .first_cluster_low_16 = 0x0000, 00273 /*uint32_t*/ .filesize = 0x00000000 00274 }; 00275 00276 static const FatDirectoryEntry_t dir_entry_tmpl = { 00277 /*uint8_t[11] */ .filename = {""}, 00278 /*uint8_t */ .attributes = VFS_FILE_ATTR_READ_ONLY, 00279 /*uint8_t */ .reserved = 0x00, 00280 /*uint8_t */ .creation_time_ms = 0x00, 00281 /*uint16_t*/ .creation_time = 0x0000, 00282 /*uint16_t*/ .creation_date = 0x4876, 00283 /*uint16_t*/ .accessed_date = 0x4876, 00284 /*uint16_t*/ .first_cluster_high_16 = 0x0000, 00285 /*uint16_t*/ .modification_time = 0x83dc, 00286 /*uint16_t*/ .modification_date = 0x4876, 00287 /*uint16_t*/ .first_cluster_low_16 = 0x0000, 00288 /*uint32_t*/ .filesize = 0x00000000 00289 }; 00290 00291 mbr_t mbr; 00292 file_allocation_table_t fat; 00293 virtual_media_t virtual_media[16]; 00294 root_dir_t dir_current; 00295 uint8_t file_count; 00296 vfs_file_change_cb_t file_change_cb; 00297 uint32_t virtual_media_idx; 00298 uint32_t fat_idx; 00299 uint32_t dir_idx; 00300 uint32_t data_start; 00301 00302 // Virtual media must be larger than the template 00303 COMPILER_ASSERT(sizeof(virtual_media) > sizeof(virtual_media_tmpl)); 00304 00305 static void write_fat(file_allocation_table_t *fat, uint32_t idx, uint16_t val) 00306 { 00307 uint32_t low_idx; 00308 uint32_t high_idx; 00309 low_idx = idx * 2 + 0; 00310 high_idx = idx * 2 + 1; 00311 00312 // Assert that this is still within the fat table 00313 if (high_idx >= ARRAY_SIZE(fat->f)) { 00314 util_assert(0); 00315 return; 00316 } 00317 00318 fat->f[low_idx] = (val >> 0) & 0xFF; 00319 fat->f[high_idx] = (val >> 8) & 0xFF; 00320 } 00321 00322 void vfs_init(const vfs_filename_t drive_name, uint32_t disk_size) 00323 { 00324 uint32_t i; 00325 uint32_t num_clusters; 00326 uint32_t total_sectors; 00327 // Clear everything 00328 memset(&mbr, 0, sizeof(mbr)); 00329 memset(&fat, 0, sizeof(fat)); 00330 fat_idx = 0; 00331 memset(&virtual_media, 0, sizeof(virtual_media)); 00332 memset(&dir_current, 0, sizeof(dir_current)); 00333 dir_idx = 0; 00334 file_count = 0; 00335 file_change_cb = file_change_cb_stub; 00336 virtual_media_idx = 0; 00337 data_start = 0; 00338 // Initialize MBR 00339 memcpy(&mbr, &mbr_tmpl, sizeof(mbr_t)); 00340 total_sectors = ((disk_size + KB(64)) / mbr.bytes_per_sector); 00341 // Make sure this is the right size for a FAT16 volume 00342 if (total_sectors < FAT_CLUSTERS_MIN * mbr.sectors_per_cluster) { 00343 util_assert(0); 00344 total_sectors = FAT_CLUSTERS_MIN * mbr.sectors_per_cluster; 00345 } else if (total_sectors > FAT_CLUSTERS_MAX * mbr.sectors_per_cluster) { 00346 util_assert(0); 00347 total_sectors = FAT_CLUSTERS_MAX * mbr.sectors_per_cluster; 00348 } 00349 if (total_sectors >= 0x10000) { 00350 mbr.total_logical_sectors = 0; 00351 mbr.big_sectors_on_drive = total_sectors; 00352 } else { 00353 mbr.total_logical_sectors = total_sectors; 00354 mbr.big_sectors_on_drive = 0; 00355 } 00356 // FAT table will likely be larger than needed, but this is allowed by the 00357 // fat specification 00358 num_clusters = total_sectors / mbr.sectors_per_cluster; 00359 mbr.logical_sectors_per_fat = (num_clusters * 2 + VFS_SECTOR_SIZE - 1) / VFS_SECTOR_SIZE; 00360 // Initailize virtual media 00361 memcpy(&virtual_media, &virtual_media_tmpl, sizeof(virtual_media_tmpl)); 00362 virtual_media[MEDIA_IDX_FAT1].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat; 00363 virtual_media[MEDIA_IDX_FAT2].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat; 00364 // Initialize indexes 00365 virtual_media_idx = MEDIA_IDX_COUNT; 00366 data_start = 0; 00367 00368 for (i = 0; i < ARRAY_SIZE(virtual_media_tmpl); i++) { 00369 data_start += virtual_media[i].length; 00370 } 00371 00372 // Initialize FAT 00373 fat_idx = 0; 00374 write_fat(&fat, fat_idx, 0xFFF8); // Media type "media_descriptor" 00375 fat_idx++; 00376 write_fat(&fat, fat_idx, 0xFFFF); // FAT12 - always 0xFFF (no meaning), FAT16 - dirty/clean (clean = 0xFFFF) 00377 fat_idx++; 00378 // Initialize root dir 00379 dir_idx = 0; 00380 dir_current.f[dir_idx] = root_dir_entry; 00381 memcpy(dir_current.f[dir_idx].filename, drive_name, sizeof(dir_current.f[0].filename)); 00382 dir_idx++; 00383 } 00384 00385 uint32_t vfs_get_total_size() 00386 { 00387 uint32_t size; 00388 if (mbr.total_logical_sectors > 0) { 00389 size = mbr.total_logical_sectors * mbr.bytes_per_sector; 00390 } else if (mbr.big_sectors_on_drive > 0) { 00391 size = mbr.big_sectors_on_drive * mbr.bytes_per_sector; 00392 } else { 00393 size = 0; 00394 util_assert(0); 00395 } 00396 return size; 00397 } 00398 00399 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) 00400 { 00401 uint32_t first_cluster; 00402 FatDirectoryEntry_t *de; 00403 uint32_t clusters; 00404 uint32_t cluster_size; 00405 uint32_t i; 00406 util_assert(filename_valid(filename)); 00407 // Compute the number of clusters in the file 00408 cluster_size = mbr.bytes_per_sector * mbr.sectors_per_cluster; 00409 clusters = (len + cluster_size - 1) / cluster_size; 00410 // Write the cluster chain to the fat table 00411 first_cluster = 0; 00412 00413 if (len > 0) { 00414 first_cluster = fat_idx; 00415 00416 for (i = 0; i < clusters - 1; i++) { 00417 write_fat(&fat, fat_idx, fat_idx + 1); 00418 fat_idx++; 00419 } 00420 00421 write_fat(&fat, fat_idx, 0xFFFF); 00422 fat_idx++; 00423 } 00424 00425 // Update directory entry 00426 if (dir_idx >= ARRAY_SIZE(dir_current.f)) { 00427 util_assert(0); 00428 return VFS_FILE_INVALID; 00429 } 00430 00431 de = &dir_current.f[dir_idx]; 00432 dir_idx++; 00433 memcpy(de, &dir_entry_tmpl, sizeof(dir_entry_tmpl)); 00434 memcpy(de->filename, filename, 11); 00435 de->filesize = len; 00436 de->first_cluster_high_16 = (first_cluster >> 16) & 0xFFFF; 00437 de->first_cluster_low_16 = (first_cluster >> 0) & 0xFFFF; 00438 00439 // Update virtual media 00440 if (virtual_media_idx >= ARRAY_SIZE(virtual_media)) { 00441 util_assert(0); 00442 return VFS_FILE_INVALID; 00443 } 00444 00445 virtual_media[virtual_media_idx].read_cb = read_zero; 00446 virtual_media[virtual_media_idx].write_cb = write_none; 00447 00448 if (0 != read_cb) { 00449 virtual_media[virtual_media_idx].read_cb = read_cb; 00450 } 00451 00452 if (0 != write_cb) { 00453 virtual_media[virtual_media_idx].write_cb = write_cb; 00454 } 00455 00456 virtual_media[virtual_media_idx].length = clusters * mbr.bytes_per_sector * mbr.sectors_per_cluster; 00457 virtual_media_idx++; 00458 file_count += 1; 00459 return de; 00460 } 00461 00462 void vfs_file_set_attr(vfs_file_t file, vfs_file_attr_bit_t attr) 00463 { 00464 FatDirectoryEntry_t *de = file; 00465 de->attributes = attr; 00466 } 00467 00468 vfs_sector_t vfs_file_get_start_sector(vfs_file_t file) 00469 { 00470 FatDirectoryEntry_t *de = file; 00471 00472 if (vfs_file_get_size(file) == 0) { 00473 return VFS_INVALID_SECTOR; 00474 } 00475 00476 return cluster_to_sector(de->first_cluster_low_16); 00477 } 00478 00479 uint32_t vfs_file_get_size(vfs_file_t file) 00480 { 00481 FatDirectoryEntry_t *de = file; 00482 return de->filesize; 00483 } 00484 00485 vfs_file_attr_bit_t vfs_file_get_attr(vfs_file_t file) 00486 { 00487 FatDirectoryEntry_t *de = file; 00488 return (vfs_file_attr_bit_t)de->attributes; 00489 } 00490 00491 void vfs_set_file_change_callback(vfs_file_change_cb_t cb) 00492 { 00493 file_change_cb = cb; 00494 } 00495 00496 void vfs_read(uint32_t requested_sector, uint8_t *buf, uint32_t num_sectors) 00497 { 00498 uint8_t i = 0; 00499 uint32_t current_sector; 00500 // Zero out the buffer 00501 memset(buf, 0, num_sectors * VFS_SECTOR_SIZE); 00502 current_sector = 0; 00503 00504 for (i = 0; i < ARRAY_SIZE(virtual_media); i++) { 00505 uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE; 00506 uint32_t vm_start = current_sector; 00507 uint32_t vm_end = current_sector + vm_sectors; 00508 00509 // Data can be used in this sector 00510 if ((requested_sector >= vm_start) && (requested_sector < vm_end)) { 00511 uint32_t sector_offset; 00512 uint32_t sectors_to_write = vm_end - requested_sector; 00513 sectors_to_write = MIN(sectors_to_write, num_sectors); 00514 sector_offset = requested_sector - current_sector; 00515 virtual_media[i].read_cb(sector_offset, buf, sectors_to_write); 00516 // Update requested sector 00517 requested_sector += sectors_to_write; 00518 num_sectors -= sectors_to_write; 00519 } 00520 00521 // If there is no more data to be read then break 00522 if (num_sectors == 0) { 00523 break; 00524 } 00525 00526 // Move to the next virtual media entry 00527 current_sector += vm_sectors; 00528 } 00529 } 00530 00531 void vfs_write(uint32_t requested_sector, const uint8_t *buf, uint32_t num_sectors) 00532 { 00533 uint8_t i = 0; 00534 uint32_t current_sector; 00535 current_sector = 0; 00536 00537 for (i = 0; i < virtual_media_idx; i++) { 00538 uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE; 00539 uint32_t vm_start = current_sector; 00540 uint32_t vm_end = current_sector + vm_sectors; 00541 00542 // Data can be used in this sector 00543 if ((requested_sector >= vm_start) && (requested_sector < vm_end)) { 00544 uint32_t sector_offset; 00545 uint32_t sectors_to_read = vm_end - requested_sector; 00546 sectors_to_read = MIN(sectors_to_read, num_sectors); 00547 sector_offset = requested_sector - current_sector; 00548 virtual_media[i].write_cb(sector_offset, buf, sectors_to_read); 00549 // Update requested sector 00550 requested_sector += sectors_to_read; 00551 num_sectors -= sectors_to_read; 00552 } 00553 00554 // If there is no more data to be read then break 00555 if (num_sectors == 0) { 00556 break; 00557 } 00558 00559 // Move to the next virtual media entry 00560 current_sector += vm_sectors; 00561 } 00562 } 00563 00564 static uint32_t read_zero(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) 00565 { 00566 uint32_t read_size = VFS_SECTOR_SIZE * num_sectors; 00567 memset(data, 0, read_size); 00568 return read_size; 00569 } 00570 00571 static void write_none(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors) 00572 { 00573 // Do nothing 00574 } 00575 00576 static uint32_t read_mbr(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) 00577 { 00578 uint32_t read_size = sizeof(mbr_t); 00579 COMPILER_ASSERT(sizeof(mbr_t) <= VFS_SECTOR_SIZE); 00580 00581 if (sector_offset != 0) { 00582 // Don't worry about reading other sectors 00583 return 0; 00584 } 00585 00586 memcpy(data, &mbr, read_size); 00587 return read_size; 00588 } 00589 00590 /* No need to handle writes to the mbr */ 00591 00592 static uint32_t read_fat(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) 00593 { 00594 uint32_t read_size = sizeof(file_allocation_table_t); 00595 COMPILER_ASSERT(sizeof(file_allocation_table_t) <= VFS_SECTOR_SIZE); 00596 00597 if (sector_offset != 0) { 00598 // Don't worry about reading other sectors 00599 return 0; 00600 } 00601 00602 memcpy(data, &fat, read_size); 00603 return read_size; 00604 } 00605 00606 /* No need to handle writes to the fat */ 00607 00608 static uint32_t read_dir(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) 00609 { 00610 if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) { 00611 // Trying to read too much of the root directory 00612 util_assert(0); 00613 return 0; 00614 } 00615 00616 // Zero buffer data is VFS_SECTOR_SIZE max 00617 memset(data, 0, VFS_SECTOR_SIZE); 00618 00619 if (sector_offset == 0) { //Handle the first 512 bytes 00620 // Copy data that is actually created in the directory 00621 memcpy(data, &dir_current.f[0], dir_idx*sizeof(FatDirectoryEntry_t)); 00622 } 00623 00624 return num_sectors * VFS_SECTOR_SIZE; 00625 } 00626 00627 static void write_dir(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors) 00628 { 00629 FatDirectoryEntry_t *old_entry; 00630 FatDirectoryEntry_t *new_entry; 00631 uint32_t start_index; 00632 uint32_t num_entries; 00633 uint32_t i; 00634 00635 if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) { 00636 // Trying to write too much of the root directory 00637 util_assert(0); 00638 return; 00639 } 00640 00641 start_index = sector_offset * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t); 00642 num_entries = num_sectors * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t); 00643 old_entry = &dir_current.f[start_index]; 00644 new_entry = (FatDirectoryEntry_t *)data; 00645 // If this is the first sector start at index 1 to get past drive name 00646 i = 0 == sector_offset ? 1 : 0; 00647 00648 for (; i < num_entries; i++) { 00649 bool same_name; 00650 00651 if (0 == memcmp(&old_entry[i], &new_entry[i], sizeof(FatDirectoryEntry_t))) { 00652 continue; 00653 } 00654 00655 // If were at this point then something has changed in the file 00656 same_name = (0 == memcmp(old_entry[i].filename, new_entry[i].filename, sizeof(new_entry[i].filename))) ? 1 : 0; 00657 // Changed 00658 file_change_cb(new_entry[i].filename, VFS_FILE_CHANGED , (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); 00659 00660 // Deleted 00661 if (0xe5 == (uint8_t)new_entry[i].filename[0]) { 00662 file_change_cb(old_entry[i].filename, VFS_FILE_DELETED , (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); 00663 continue; 00664 } 00665 00666 // Created 00667 if (!same_name && filename_valid(new_entry[i].filename)) { 00668 file_change_cb(new_entry[i].filename, VFS_FILE_CREATED , (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]); 00669 continue; 00670 } 00671 } 00672 00673 memcpy(&dir_current.f[start_index], data, num_sectors * VFS_SECTOR_SIZE); 00674 } 00675 00676 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) 00677 { 00678 // Do nothing 00679 } 00680 00681 static uint32_t cluster_to_sector(uint32_t cluster_idx) 00682 { 00683 uint32_t sectors_before_data = data_start / mbr.bytes_per_sector; 00684 return sectors_before_data + (cluster_idx - 2) * mbr.sectors_per_cluster; 00685 } 00686 00687 static bool filename_valid(const vfs_filename_t filename) 00688 { 00689 // Information on valid 8.3 filenames can be found in 00690 // the microsoft hardware whitepaper: 00691 // 00692 // Microsoft Extensible Firmware Initiative 00693 // FAT32 File System Specification 00694 // FAT: General Overview of On-Disk Format 00695 const char invalid_starting_chars[] = { 00696 0xE5, // Deleted 00697 0x00, // Deleted (and all following entries are free) 00698 0x20, // Space not allowed as first character 00699 }; 00700 uint32_t i; 00701 00702 // Check for invalid starting characters 00703 for (i = 0; i < sizeof(invalid_starting_chars); i++) { 00704 if (invalid_starting_chars[i] == filename[0]) { 00705 return false; 00706 } 00707 } 00708 00709 // Make sure all the characters are valid 00710 for (i = 0; i < sizeof(vfs_filename_t); i++) { 00711 if (!filename_character_valid(filename[i])) { 00712 return false; 00713 } 00714 } 00715 00716 // All checks have passed so filename is valid 00717 return true; 00718 } 00719 00720 static bool filename_character_valid(char character) 00721 { 00722 const char invalid_chars[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C}; 00723 uint32_t i; 00724 00725 // Lower case characters are not allowed 00726 if ((character >= 'a') && (character <= 'z')) { 00727 return false; 00728 } 00729 00730 // Values less than 0x20 are not allowed except 0x5 00731 if ((character < 0x20) && (character != 0x5)) { 00732 return false; 00733 } 00734 00735 // Check for special characters that are not allowed 00736 for (i = 0; i < sizeof(invalid_chars); i++) { 00737 if (invalid_chars[i] == character) { 00738 return false; 00739 } 00740 } 00741 00742 // All of the checks have passed so this is a valid file name character 00743 return true; 00744 }
Generated on Tue Jul 12 2022 15:37:28 by
1.7.2