_mfs_error MFS_Find_next_slave ( MFS_DRIVE_STRUCT_PTR drive_ptr, /*[IN] drive context */ void *search_next_ptr /*[IN] address of search data block indicating the current criteria and the results ** of the last search results of this search are placed in this data block */ ) { MFS_SEARCH_DATA_PTR transfer_ptr; MFS_INTERNAL_SEARCH_PTR internal_search_ptr; MFS_DIR_ENTRY_PTR dir_entry_ptr; _mfs_error error_code; uint32_t len; bool found; bool match_all; bool eightdotthree = FALSE; char *lfn; char sname[SFILENAME_SIZE+1]; uint32_t dotfile = 0; MFS_DIR_ENTRY saved_dir_entry; transfer_ptr = (MFS_SEARCH_DATA_PTR) search_next_ptr; error_code = MFS_NO_ERROR; found = FALSE; if ( transfer_ptr ) { internal_search_ptr = &transfer_ptr->INTERNAL_SEARCH_DATA; if ( MFS_alloc_path(&lfn)!= MFS_NO_ERROR ) { return MFS_INSUFFICIENT_MEMORY; } match_all = MFS_Check_search_string_for_all(internal_search_ptr->SRC_PTR); if ( !match_all ) { dotfile = MFS_Is_dot_directory(internal_search_ptr->SRC_PTR); if ( dotfile == 0 ) { eightdotthree = MFS_Check_search_string_for_8dot3( internal_search_ptr->SRC_PTR); } } do { dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, NULL, &internal_search_ptr->CURRENT_CLUSTER, &internal_search_ptr->DIR_ENTRY_INDEX, &internal_search_ptr->PREV_CLUSTER, internal_search_ptr->ATTRIBUTE & (~ATTR_EXCLUSIVE), &error_code); if ( dir_entry_ptr == NULL && !error_code ) { error_code = MFS_FILE_NOT_FOUND; break; } if ( internal_search_ptr->CURRENT_CLUSTER == CLUSTER_INVALID ) { error_code = MFS_FILE_NOT_FOUND; break; } if ( dir_entry_ptr == NULL ) { break; } saved_dir_entry=*dir_entry_ptr; /* Make sure the entry is not an LFN entry */ if ( *dir_entry_ptr->ATTRIBUTE != MFS_ATTR_LFN ) { MFS_Compress_nondotfile (dir_entry_ptr->NAME, sname); if ( match_all ) { found = TRUE; } else { if ( dotfile != 0 ) { if ( dotfile == 1 ) { found = internal_search_ptr->FULLNAME[0] == dir_entry_ptr->NAME[0]; } else if ( dotfile == 2 ) { found = (internal_search_ptr->FULLNAME[0] == dir_entry_ptr->NAME[0]) && (internal_search_ptr->FULLNAME[1] == dir_entry_ptr->NAME[1]); } else { found = FALSE; /* This shouldn't happen */ } } else if ( eightdotthree ) { found = MFS_Wildcard_match(internal_search_ptr->FILENAME, dir_entry_ptr->NAME); } else { if ( MFS_get_lfn_dir_cluster(drive_ptr, search_next_ptr, sname, lfn) == MFS_NO_ERROR ) { found = MFS_lfn_match(internal_search_ptr->SRC_PTR, lfn, 0); } else { found = MFS_lfn_match(internal_search_ptr->SRC_PTR, sname, 0); } } } } if ( !error_code ) { error_code = MFS_Increment_dir_index(drive_ptr, &internal_search_ptr->CURRENT_CLUSTER, &internal_search_ptr->DIR_ENTRY_INDEX, &internal_search_ptr->PREV_CLUSTER); } } while ( (error_code == MFS_NO_ERROR) && (found == FALSE) ); if ( error_code == MFS_NO_ERROR ) { transfer_ptr->ATTRIBUTE = mqx_dtohc(saved_dir_entry.ATTRIBUTE); transfer_ptr->TIME = mqx_dtohs(saved_dir_entry.TIME); transfer_ptr->DATE = mqx_dtohs(saved_dir_entry.DATE); transfer_ptr->FILE_SIZE = mqx_dtohl(saved_dir_entry.FILE_SIZE); /* Transfer the filename */ len = _strnlen(sname,13); if ( sname[len-1] == '.' ) { sname[len-1] = '\0'; } strncpy(transfer_ptr->NAME, sname, 13); } MFS_free_path((void *)lfn); } else { error_code = MFS_INVALID_MEMORY_BLOCK_ADDRESS; } return(error_code); }
uint32_t MFS_Write ( MFS_HANDLE_PTR handle, MFS_DRIVE_STRUCT_PTR drive_ptr, uint32_t num_bytes, /*[IN] number of bytes to be written */ char *buffer_address, /*[IN/OUT] bytes are written from this buffer */ _mfs_error_ptr error_ptr /*[IN/OUT] error code is written to this address */ ) { uint32_t bytes_written; uint32_t copy_size; uint32_t cluster_offset; uint32_t sector_number, sector_index; uint32_t sector_offset; uint32_t whole_sectors; uint32_t cont_sectors; uint32_t proc_sectors; _mfs_error error, temp_error; uint32_t file_size; uint32_t next_cluster; bool need_hwread; uint32_t location; uint32_t num_zeros; uint32_t zeros_written; uint32_t zero_size; #if MFSCFG_READ_ONLY_CHECK if (MFS_is_read_only (drive_ptr)) { MFS_set_error_and_return(error_ptr,MFS_DISK_IS_WRITE_PROTECTED,0); } #endif if ( buffer_address == NULL ) { MFS_set_error_and_return(error_ptr,MFS_INVALID_PARAMETER,0); } if ( num_bytes == 0 ) { MFS_set_error_and_return(error_ptr,MFS_NO_ERROR,0); } error = MFS_lock_dos_disk( drive_ptr ); if ( error != MFS_NO_ERROR ) { MFS_set_error_and_return(error_ptr,error,0); } if ( handle->ACCESS == MFS_ACCESS_READ_ONLY ) { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,MFS_ACCESS_DENIED,0); } /* ** Setup the current cluster. If this is the first time writing to the file, a cluster needs to be added. */ if ( handle->CURRENT_CLUSTER == 0 ) { handle->PREVIOUS_CLUSTER = 0; handle->CURRENT_CLUSTER = clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER); if ( handle->CURRENT_CLUSTER==0 ) { next_cluster = MFS_Find_unused_cluster_from(drive_ptr,drive_ptr->NEXT_FREE_CLUSTER); if ( next_cluster != CLUSTER_INVALID ) { clustod(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER, next_cluster); handle->TOUCHED = 1; error = MFS_Put_fat(drive_ptr, next_cluster, CLUSTER_EOF); if ( error == MFS_NO_ERROR ) { handle->CURRENT_CLUSTER = next_cluster; } else { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,error,0); } } else { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,MFS_DISK_FULL,0); } } } else if ( handle->CURRENT_CLUSTER == CLUSTER_EOF ) { error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER); if ( MFS_NO_ERROR != error ) { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,error,0); } } else if ( handle->CURRENT_CLUSTER > drive_ptr->LAST_CLUSTER ) { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,MFS_DISK_FULL,0); } /* Make sure location (local variable) never points behind the end of file */ file_size = mqx_dtohl(handle->DIR_ENTRY.FILE_SIZE); location = (handle->LOCATION > file_size) ? file_size : handle->LOCATION; /* Calculate sector number and offsets within cluster and sector */ cluster_offset = OFFSET_WITHIN_CLUSTER(location); sector_index = CLUSTER_OFFSET_TO_SECTOR(cluster_offset); sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER) + sector_index; sector_offset = OFFSET_WITHIN_SECTOR(location); /* Calculate possible gap to fill in by zeros if writing behind the end of file */ num_zeros = handle->LOCATION - location; zeros_written = 0; bytes_written = 0; /* Write zeros to fill in gap if LOCATION points behind the end of file */ while (zeros_written < num_zeros) { /* If offset is non-zero, then reading the data is required */ error = MFS_Read_data_sector(drive_ptr, handle, sector_number, sector_offset != 0); if ( error != MFS_NO_ERROR ) break; /* Zero the buffer */ zero_size = min(num_zeros-zeros_written, drive_ptr->BPB.SECTOR_SIZE-sector_offset); _mem_zero(&drive_ptr->DATA_SECTOR_PTR[sector_offset], zero_size); drive_ptr->DATA_SECTOR_DIRTY = TRUE; if ( drive_ptr->WRITE_CACHE_POLICY == MFS_WRITE_THROUGH_CACHE ) { error = MFS_Flush_data_sector_buffer(drive_ptr); if ( error != MFS_NO_ERROR ) break; } zeros_written += zero_size; sector_offset += zero_size; /* ** Check to see if we need to advance to the next sector, which has ** the side effect of increasing the cluster number if required. */ if ( sector_offset >= drive_ptr->BPB.SECTOR_SIZE ) { temp_error = MFS_next_data_sector(drive_ptr, handle, §or_index, §or_number); if (temp_error == MFS_EOF) { /* Always allocate new cluster, there is something to be written for sure */ error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER); if ( MFS_NO_ERROR == error ) { sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER); sector_index = 0; } } else { error = temp_error; } sector_offset = 0; } } /* Write partial sector if sector_offset is non-zero */ if ((sector_offset != 0) && (error == MFS_NO_ERROR)) { /* Offset is non-zero, reading the data is required */ error = MFS_Read_data_sector(drive_ptr, handle, sector_number, TRUE); if (error == MFS_NO_ERROR) { /* The requested lenght of data may span the sector to it's end */ copy_size = min(num_bytes, drive_ptr->BPB.SECTOR_SIZE-sector_offset); _mem_copy(buffer_address, &drive_ptr->DATA_SECTOR_PTR[sector_offset], copy_size); drive_ptr->DATA_SECTOR_DIRTY = TRUE; if (drive_ptr->WRITE_CACHE_POLICY == MFS_WRITE_THROUGH_CACHE) { error = MFS_Flush_data_sector_buffer(drive_ptr); } if (error == MFS_NO_ERROR) { bytes_written = copy_size; /* ** Check to see if we need to advance to the next sector, which has ** the side effect of increasing the cluster number if required. */ if ((sector_offset + bytes_written) >= drive_ptr->BPB.SECTOR_SIZE) { temp_error = MFS_next_data_sector(drive_ptr, handle, §or_index, §or_number); /* Only an error if we are not done writing and can't extend the chain */ if (bytes_written < num_bytes) { if (temp_error == MFS_EOF) { /* Allocate new cluster */ error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER); /* Update sector_number and index unconditionally - if there was an error the value is never used anyways. */ sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER); sector_index = 0; } else { error = temp_error; } } } } } } /* Check whether the application buffer is properly aligned */ if ((((uint32_t)buffer_address+bytes_written) & drive_ptr->ALIGNMENT_MASK) == 0) { /* Yes, use zero copy approach */ whole_sectors = (num_bytes - bytes_written) >> drive_ptr->SECTOR_POWER; while ((whole_sectors > 0) && (error == MFS_NO_ERROR)) { cont_sectors = drive_ptr->BPB.SECTORS_PER_CLUSTER - sector_index; if (cont_sectors > whole_sectors) cont_sectors = whole_sectors; error = MFS_Write_device_sectors(drive_ptr, sector_number, cont_sectors, MFSCFG_MAX_WRITE_RETRIES, buffer_address+bytes_written, &proc_sectors); if (proc_sectors > 0) { bytes_written += proc_sectors * drive_ptr->BPB.SECTOR_SIZE; whole_sectors -= proc_sectors; /* Advance to next unprocessed sector */ sector_index += proc_sectors - 1; temp_error = MFS_next_data_sector(drive_ptr, handle, §or_index, §or_number); /* Go on only if we are not done writing yet */ if ((error == MFS_NO_ERROR) && (bytes_written < num_bytes)) { if (temp_error == MFS_EOF) { /* Allocate new cluster */ error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER); /* Update sector_number and index unconditionally - if there was an error the value is never used anyways. */ sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER); sector_index = 0; } else { error = temp_error; } } } } }
uint32_t MFS_Read ( MFS_HANDLE_PTR handle, /*[IN] file handle upon which the action is to be taken */ MFS_DRIVE_STRUCT_PTR drive_ptr, uint32_t num_bytes, /*[IN] number of bytes to be read */ char *buffer_address, /*[IN/OUT] bytes are read into this buffer */ _mfs_error_ptr error_ptr /*[IN/OUT] error code is written to this address */ ) { uint32_t location; uint32_t bytes_read; uint32_t bytes_left_in_file; uint32_t copy_size; uint32_t cluster_offset; uint32_t sector_number, sector_index; uint32_t sector_offset; uint32_t whole_sectors; uint32_t cont_sectors; uint32_t proc_sectors; _mfs_error error, temp_error; bool eof_reached; uint32_t file_size; if ( num_bytes == 0 ) { MFS_set_error_and_return(error_ptr,MFS_NO_ERROR,0); } if ( buffer_address == NULL ) { MFS_set_error_and_return(error_ptr,MFS_INVALID_PARAMETER,0); } error = MFS_lock_dos_disk(drive_ptr); if ( error != MFS_NO_ERROR ) { MFS_set_error_and_return(error_ptr,error,0); } if ( handle->ACCESS != MFS_ACCESS_READ_ONLY && handle->ACCESS != MFS_ACCESS_READ_WRITE ) { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,MFS_ACCESS_DENIED,0); } if ( handle->CURRENT_CLUSTER == 0 ) { handle->PREVIOUS_CLUSTER = 0; handle->CURRENT_CLUSTER = clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER); } else if ( handle->CURRENT_CLUSTER == CLUSTER_EOF ) { MFS_unlock(drive_ptr,FALSE); MFS_set_error_and_return(error_ptr,MFS_EOF,0); } bytes_read = 0; eof_reached = FALSE; location = handle->LOCATION; /* ** Can't read past file size */ file_size = mqx_dtohl(handle->DIR_ENTRY.FILE_SIZE); if ( location > file_size ) { location = file_size; } bytes_left_in_file = file_size - location; if ( num_bytes > bytes_left_in_file ) { eof_reached = TRUE; num_bytes = bytes_left_in_file; } if ( bytes_left_in_file ) { /* ** Read the number of bytes from the current file ** position to the end of the current cluster */ cluster_offset = OFFSET_WITHIN_CLUSTER(location); sector_index = CLUSTER_OFFSET_TO_SECTOR(cluster_offset); sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER) + sector_index; sector_offset = OFFSET_WITHIN_SECTOR(location); /* Read partial sector if sector_offet is non-zero */ if (sector_offset != 0) { error = MFS_Read_data_sector(drive_ptr, handle, sector_number, TRUE); if ( error == MFS_NO_ERROR ) { /* The requested lenght of data may span the sector to it's end */ copy_size = min(num_bytes, drive_ptr->BPB.SECTOR_SIZE-sector_offset); _mem_copy(&drive_ptr->DATA_SECTOR_PTR[sector_offset], buffer_address, copy_size); bytes_read=copy_size; /* ** Check to see if we need to advance to the next sector, which has ** the side effect of increasing the cluster number if required. */ if ( (sector_offset+bytes_read) >= drive_ptr->BPB.SECTOR_SIZE ) { temp_error = MFS_next_data_sector(drive_ptr, handle, §or_index, §or_number); /* Only an error if we are not done reading */ if ( bytes_read<num_bytes ) { error = temp_error; } } } } /* Check whether the application buffer is properly aligned */ if ((((uint32_t)buffer_address+bytes_read) & drive_ptr->ALIGNMENT_MASK) == 0) { /* Yes, use zero copy approach */ whole_sectors = (num_bytes - bytes_read) >> drive_ptr->SECTOR_POWER; while ((whole_sectors > 0) && (error == MFS_NO_ERROR)) { cont_sectors = drive_ptr->BPB.SECTORS_PER_CLUSTER - sector_index; if (cont_sectors > whole_sectors) cont_sectors = whole_sectors; error = MFS_Read_device_sectors(drive_ptr, sector_number, cont_sectors, MFSCFG_MAX_READ_RETRIES, buffer_address+bytes_read, &proc_sectors); if (proc_sectors > 0) { bytes_read += proc_sectors * drive_ptr->BPB.SECTOR_SIZE; whole_sectors -= proc_sectors; /* Advance to next unprocessed sector */ sector_index += proc_sectors - 1; temp_error = MFS_next_data_sector(drive_ptr, handle, §or_index, §or_number); /* Only an error if we are not done reading */ if ((error==MFS_NO_ERROR) && (bytes_read<num_bytes)) { error = temp_error; } } } } else {
uint32_t MFS_Move_file_pointer ( MFS_HANDLE_PTR handle, MFS_DRIVE_STRUCT_PTR drive_ptr, _mfs_error_ptr error_ptr /*[IN/OUT] resulting error code is written to this address*/ ) { uint32_t position_after_seek, position_before_seek; uint32_t current_cluster, previous_cluster, first_cluster, skip_clusters, k; _mfs_error error_code; error_code = MFS_lock_dos_disk( drive_ptr ); if ( error_code != MFS_NO_ERROR ) { if ( error_ptr != NULL ) { *error_ptr = error_code; } return 0; } position_after_seek = handle->LOCATION; MFS_LOG(printf("seek to %d\n",position_after_seek)); /* ** Cannot move ahead of the beginning of the file; force beginning. */ if ( error_code == MFS_NO_ERROR ) { /* ** There are four cases ** ** 1) Seeking to beginning of file (position_after_seek=0, cluster=0) ** 2) No change in position (position_after_seek==position_before_seek) ** 2) Seeking ahead of current file pointer ** 3) Seeking behind current file pointer */ /* ** Cannot move beyond the end of file ! */ if ( position_after_seek> mqx_dtohl(handle->DIR_ENTRY.FILE_SIZE) ) // + 1 { position_after_seek = mqx_dtohl(handle->DIR_ENTRY.FILE_SIZE); // - 1 error_code = MFS_EOF; } current_cluster = 0; previous_cluster = 0; first_cluster = clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER); MFS_LOG(printf("first_cluster = %d\n",first_cluster)); /* ** Set the current_cluster correctly. ** If we're moving ahead, don't start from the beginning. */ position_before_seek = CLUSTER_BOUNDARY(handle->SAVED_POSITION); if ( handle->CURRENT_CLUSTER==0 ) { handle->CURRENT_CLUSTER = first_cluster; handle->PREVIOUS_CLUSTER = 0; position_before_seek = 0; } if ( position_after_seek == 0 ) { current_cluster = first_cluster; previous_cluster = 0; } else if ( position_after_seek == position_before_seek ) { current_cluster = handle->CURRENT_CLUSTER; previous_cluster = handle->PREVIOUS_CLUSTER; } else { if ( position_after_seek < position_before_seek ) { position_before_seek = 0; current_cluster = first_cluster; previous_cluster = 0; } else { current_cluster = handle->CURRENT_CLUSTER; previous_cluster = handle->PREVIOUS_CLUSTER; } MFS_LOG(printf("current cluster = %d\n",current_cluster)); if ( current_cluster && (current_cluster!=CLUSTER_EOF) ) { /* ** How many clusters do we need to skip? */ skip_clusters = (position_after_seek - position_before_seek) >> drive_ptr->CLUSTER_POWER_BYTES; for ( k = 0; k < skip_clusters; k++ ) { previous_cluster = current_cluster; error_code = MFS_get_cluster_from_fat(drive_ptr, previous_cluster, ¤t_cluster); if ( error_code != MFS_NO_ERROR ) { break; } if ( current_cluster==CLUSTER_EOF ) { error_code = MFS_EOF; break; } else if ( (current_cluster < CLUSTER_MIN_GOOD) || (current_cluster > drive_ptr->LAST_CLUSTER) ) { error_code = MFS_BAD_DISK_UNIT; break; } MFS_LOG(printf("skip, current cluster = %d\n",current_cluster)); } } else { error_code = MFS_EOF; } }
/*! * \brief Used to set the MFS drive parameters for a unit. * * This function assumes that the boot sector of the drive is stored in * the drive's sector buffer. This function is called after MFS is * initialized, or after the drive has been formatted. * * NOTE: It is assumed that the drive is locked by the calling function. * * \param drive_ptr * * \return uint32_t Error code. */ uint32_t MFS_Mount_drive_internal( MFS_DRIVE_STRUCT_PTR drive_ptr) { BIOS_PARAM_STRUCT_DISK_PTR bpb_ptr; BIOS_PARAM32_STRUCT_DISK_PTR bpb32_ptr; FILESYSTEM_INFO_DISK_PTR fsinfo_ptr; uint32_t reserved_sectors; uint32_t root_dir_sectors; uint32_t data_sectors; uint32_t cluster_count; uint32_t bpb_sector_size; uint32_t bpb_sector_mult; int error_code; int result = MFS_NO_ERROR; uint8_t *boot_sector; drive_ptr->DOS_DISK = false; error_code = MFS_sector_cache_invalidate(drive_ptr, 0, 0); if (error_code != MFS_NO_ERROR) { return error_code; } error_code = MFS_sector_map(drive_ptr, BOOT_SECTOR, (void **)&boot_sector, MFS_MAP_MODE_READONLY, 0); if (error_code != MFS_NO_ERROR) { return error_code; } /* ** Extract the drive parameters (BIOS Parameter Block) from the BOOT Record. */ bpb_ptr = (BIOS_PARAM_STRUCT_DISK_PTR)boot_sector; bpb32_ptr = (BIOS_PARAM32_STRUCT_DISK_PTR)(boot_sector + sizeof(BIOS_PARAM_STRUCT_DISK)); /* ** Next, check to see that the BOOT record is that of a DOS disk. If not, ** the drive will have to be formatted by the upper layer before the drive ** can be 'mounted'. */ if ((boot_sector[0] != MFS_DOS30_JMP) && (boot_sector[0] != MFS_DOS30_B)) { result = MFS_NOT_A_DOS_DISK; } if (result == MFS_NO_ERROR) { /* ** Always use storage device sector size. ** If BPB sector size is larger, then recalculate other parameters accordingly. ** In any case, BPB sector size has to be multiple of device sector size, the code explicitly checks this. */ bpb_sector_size = mqx_dtohs(bpb_ptr->SECTOR_SIZE); if (bpb_sector_size % drive_ptr->SECTOR_SIZE) { result = MFS_NOT_A_DOS_DISK; } } if (result == MFS_NO_ERROR) { /* Sector values from BPB are to be multiplied by this factor */ bpb_sector_mult = bpb_sector_size / drive_ptr->SECTOR_SIZE; reserved_sectors = mqx_dtohs(bpb_ptr->RESERVED_SECTORS) * bpb_sector_mult; drive_ptr->SECTORS_PER_CLUSTER = mqx_dtohc(bpb_ptr->SECTORS_PER_CLUSTER) * bpb_sector_mult; drive_ptr->CLUSTER_POWER_SECTORS = ilog2(drive_ptr->SECTORS_PER_CLUSTER); drive_ptr->CLUSTER_POWER_BYTES = drive_ptr->SECTOR_POWER + drive_ptr->CLUSTER_POWER_SECTORS; drive_ptr->CLUSTER_SIZE_BYTES = drive_ptr->SECTOR_SIZE * drive_ptr->SECTORS_PER_CLUSTER; drive_ptr->NUMBER_OF_FAT = mqx_dtohc(bpb_ptr->NUMBER_OF_FAT); drive_ptr->ROOT_ENTRIES = mqx_dtohs(bpb_ptr->ROOT_ENTRIES); drive_ptr->SECTORS_PER_FAT = mqx_dtohs(bpb_ptr->SECTORS_PER_FAT); if (drive_ptr->SECTORS_PER_FAT == 0) { drive_ptr->SECTORS_PER_FAT = mqx_dtohl(bpb32_ptr->FAT_SIZE); } drive_ptr->SECTORS_PER_FAT *= bpb_sector_mult; drive_ptr->MEGA_SECTORS = mqx_dtohs(bpb_ptr->NUMBER_SECTORS); if (drive_ptr->MEGA_SECTORS == 0) { drive_ptr->MEGA_SECTORS = mqx_dtohl(bpb_ptr->MEGA_SECTORS); } drive_ptr->MEGA_SECTORS *= bpb_sector_mult; /* Determine FAT type by calculating the count of clusters on disk */ drive_ptr->ENTRIES_PER_SECTOR = drive_ptr->SECTOR_SIZE / sizeof(DIR_ENTRY_DISK); root_dir_sectors = drive_ptr->ROOT_ENTRIES / drive_ptr->ENTRIES_PER_SECTOR; data_sectors = drive_ptr->MEGA_SECTORS - reserved_sectors - root_dir_sectors - (drive_ptr->NUMBER_OF_FAT * drive_ptr->SECTORS_PER_FAT); cluster_count = data_sectors / drive_ptr->SECTORS_PER_CLUSTER; /* Now we have cluster count, so we can determine FAT type */ if (cluster_count < 4085) { drive_ptr->FAT_TYPE = MFS_FAT12; } else if (cluster_count < 65525) { drive_ptr->FAT_TYPE = MFS_FAT16; } else { drive_ptr->FAT_TYPE = MFS_FAT32; } drive_ptr->CLUSTER_SIZE_BYTES = drive_ptr->SECTOR_SIZE * drive_ptr->SECTORS_PER_CLUSTER; drive_ptr->CLUSTER_POWER_BYTES = drive_ptr->SECTOR_POWER + drive_ptr->CLUSTER_POWER_SECTORS; drive_ptr->FREE_COUNT = FSI_UNKNOWN; /* This is the unknown value */ drive_ptr->NEXT_FREE_CLUSTER = FSI_UNKNOWN; /* MFS will calculate it later */ drive_ptr->FAT_START_SECTOR = reserved_sectors; drive_ptr->DATA_START_SECTOR = drive_ptr->FAT_START_SECTOR + (drive_ptr->SECTORS_PER_FAT * drive_ptr->NUMBER_OF_FAT) + root_dir_sectors; if (drive_ptr->FAT_TYPE != MFS_FAT32) { /* FAT12 or FAT16 */ drive_ptr->ROOT_START_SECTOR = drive_ptr->FAT_START_SECTOR + (drive_ptr->SECTORS_PER_FAT * drive_ptr->NUMBER_OF_FAT); drive_ptr->ROOT_CLUSTER = 0; MFS_chain_forge(drive_ptr, &drive_ptr->ROOT_CHAIN, drive_ptr->ROOT_START_SECTOR, root_dir_sectors); } else if (mqx_dtohs(bpb32_ptr->FS_VER) > MFS_FAT32_VER) { /* Unsupported FAT32 level */ result = MFS_ERROR_UNKNOWN_FS_VERSION; } else { /* Supported FAT32 */ drive_ptr->ROOT_CLUSTER = mqx_dtohl(bpb32_ptr->ROOT_CLUSTER); drive_ptr->ROOT_START_SECTOR = 0; MFS_chain_init(drive_ptr, &drive_ptr->ROOT_CHAIN, drive_ptr->ROOT_CLUSTER); drive_ptr->FS_INFO = mqx_dtohs(bpb32_ptr->FS_INFO); } } error_code = MFS_sector_unmap(drive_ptr, BOOT_SECTOR, 0); if (result == MFS_NO_ERROR) { result = error_code; } if (result != MFS_NO_ERROR) { return result; } if (drive_ptr->FAT_TYPE == MFS_FAT32) { /* ** Reset the FSInfo->Free_Count and the FSInfo->Next_Free to ** unknown (0xFFFFFFFF). MFS uses it's own internal version of these ** fields. If Windows uses the same disk, it will recalculate the ** correct fields the first time it mounts the drive. */ error_code = MFS_sector_map(drive_ptr, drive_ptr->FS_INFO, (void **)&fsinfo_ptr, MFS_is_read_only(drive_ptr) ? MFS_MAP_MODE_READONLY : MFS_MAP_MODE_MODIFY, 0); if (error_code == MFS_NO_ERROR) { if ((mqx_dtohl(fsinfo_ptr->LEAD_SIG) == FSI_LEADSIG) && (mqx_dtohl(fsinfo_ptr->STRUCT_SIG) == FSI_STRUCTSIG) && (mqx_dtohl(fsinfo_ptr->TRAIL_SIG) == FSI_TRAILSIG)) { drive_ptr->FREE_COUNT = mqx_dtohl(fsinfo_ptr->FREE_COUNT); drive_ptr->NEXT_FREE_CLUSTER = mqx_dtohl(fsinfo_ptr->NEXT_FREE); } if (!MFS_is_read_only(drive_ptr)) { mqx_htodl(fsinfo_ptr->LEAD_SIG, FSI_LEADSIG); mqx_htodl(fsinfo_ptr->STRUCT_SIG, FSI_STRUCTSIG); mqx_htodl(fsinfo_ptr->FREE_COUNT, FSI_UNKNOWN); /* compute it */ mqx_htodl(fsinfo_ptr->NEXT_FREE, FSI_UNKNOWN); /* compute it */ mqx_htodl(fsinfo_ptr->TRAIL_SIG, FSI_TRAILSIG); } error_code = MFS_sector_unmap(drive_ptr, drive_ptr->FS_INFO, !MFS_is_read_only(drive_ptr)); } if (result == MFS_NO_ERROR) { result = error_code; } } drive_ptr->LAST_CLUSTER = (drive_ptr->MEGA_SECTORS - drive_ptr->DATA_START_SECTOR) / drive_ptr->SECTORS_PER_CLUSTER + 1; drive_ptr->CURRENT_DIR[0] = '\\'; /* Root dir */ drive_ptr->CURRENT_DIR[1] = '\0'; drive_ptr->CUR_DIR_CLUSTER = drive_ptr->ROOT_CLUSTER; drive_ptr->CUR_DIR_CHAIN_PTR = &drive_ptr->ROOT_CHAIN; if (result == MFS_NO_ERROR) { drive_ptr->DOS_DISK = true; } return result; }