_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); }
void *MFS_Create_file ( MFS_DRIVE_STRUCT_PTR drive_ptr, unsigned char attr, /*[IN] attribute for created file*/ char *pathname, /*[IN] directory and filename of the file to be created */ _mfs_error_ptr error_ptr /*[IN/OUT] error code is written to this address */ ) { MFS_HANDLE_PTR handle; MFS_HANDLE_PTR next_handle; MFS_DIR_ENTRY_PTR dir_entry_ptr; TIME_STRUCT time; DATE_STRUCT clk_time; uint32_t dir_cluster; uint32_t dir_index; char access; _mfs_error error_code, saved_code = 0; if ( (pathname == NULL) || (*pathname == '\0') ) { *error_ptr = MFS_INVALID_PARAMETER; return( NULL ); } #if MFSCFG_READ_ONLY_CHECK if (MFS_is_read_only (drive_ptr)) { *error_ptr = MFS_DISK_IS_WRITE_PROTECTED; return NULL; } #endif error_code = MFS_lock_dos_disk( drive_ptr ); if ( error_code != MFS_NO_ERROR ) { *error_ptr = error_code; return( NULL ); } handle = NULL; attr &= (MFS_ATTR_READ_ONLY | MFS_ATTR_HIDDEN_FILE | MFS_ATTR_SYSTEM_FILE | MFS_ATTR_ARCHIVE | MFS_ATTR_VOLUME_NAME); attr |= MFS_ATTR_ARCHIVE; access = (attr & MFS_ATTR_READ_ONLY) ? MFS_ACCESS_READ_ONLY : MFS_ACCESS_READ_WRITE; dir_entry_ptr = MFS_Create_entry_slave(drive_ptr, attr, pathname, &dir_cluster, &dir_index, &error_code, TRUE); if ( (dir_entry_ptr != NULL) && !(attr & MFS_ATTR_VOLUME_NAME) ) { handle = MFS_Get_handle(drive_ptr,dir_entry_ptr); if ( handle != NULL ) { handle->DIR_CLUSTER = dir_cluster; handle->DIR_INDEX = dir_index; handle->ACCESS = access; handle->CURRENT_CLUSTER = 0; handle->PREVIOUS_CLUSTER = 0; /* ** If file exists, overwrite and set size to 0 */ if ( error_code == MFS_FILE_EXISTS ) { _time_get(&time); _time_to_date(&time, &clk_time); NORMALIZE_DATE(&clk_time); saved_code = MFS_Release_chain(drive_ptr, clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER)); if ( saved_code == MFS_NO_ERROR || saved_code == MFS_LOST_CHAIN ) { clustod(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER, 0); mqx_htodl(handle->DIR_ENTRY.FILE_SIZE, 0L); mqx_htodc(handle->DIR_ENTRY.ATTRIBUTE, attr); mqx_htods(handle->DIR_ENTRY.TIME, PACK_TIME(clk_time)); mqx_htods(handle->DIR_ENTRY.DATE, PACK_DATE(clk_time)); error_code = MFS_Update_entry(drive_ptr, handle); /* ** If the same file is already open, mark it as 'freshly ** truncated' so reads and writes don't clobber any data. */ if ( error_code == MFS_NO_ERROR ) { next_handle = (MFS_HANDLE_PTR) _queue_head(&drive_ptr->HANDLE_LIST); while ( next_handle ) { if ( next_handle->DIR_CLUSTER == dir_cluster && next_handle->DIR_INDEX == dir_index ) { next_handle->CURRENT_CLUSTER = 0; next_handle->PREVIOUS_CLUSTER = 0; } next_handle = (MFS_HANDLE_PTR) _queue_next(&drive_ptr->HANDLE_LIST, (QUEUE_ELEMENT_STRUCT_PTR) next_handle); } } } } /* ** No need to update the disk image if we didn't change anything. */ if ( (mqx_dtohc(handle->DIR_ENTRY.ATTRIBUTE) != attr) && (error_code == MFS_NO_ERROR) ) { mqx_htodc(handle->DIR_ENTRY.ATTRIBUTE, attr); error_code = MFS_Update_entry(drive_ptr, handle); } } else { error_code = MFS_INSUFFICIENT_MEMORY; } } MFS_unlock(drive_ptr,FALSE); if ( error_code == MFS_NO_ERROR && saved_code == MFS_LOST_CHAIN ) { *error_ptr = saved_code; } else { *error_ptr = error_code; } return((void *)handle); }
MFS_DIR_ENTRY_PTR MFS_Find_directory_entry ( MFS_DRIVE_STRUCT_PTR drive_ptr, /*[IN] drive context */ char *file_ptr, /*[IN] specific name to search for, if NULL then first dir entry */ uint32_t *start_cluster_ptr, /*[IN] start searching in this cluster **[OUT] set to the cluster number in which search was satisfied */ uint32_t *dir_index_ptr, /*[IN] start searching at this directory entry **[OUT] if entry is found the index of the next entry is returned */ uint32_t *prev_cluster_ptr, /* [IN] set to the cluster number previous to start_cluster ** [OUT] set to the cluster number previous to *dir_cluster_ptr */ unsigned char attribute, /*[IN] search attribute, as per Find_first_file */ _mfs_error_ptr error_ptr /* The pointer carries the error infomation */ ) { MFS_DIR_ENTRY_PTR dir_entry_ptr = NULL; char *lfn_ptr = NULL; bool found; bool lfn_flag; bool maybe = FALSE; bool found_lfn = FALSE; uint32_t current_cluster, current_index; _mfs_error error_code; uint32_t lfn_len = 0; uint16_t entries_per_sector; uint16_t k, i; char lfn_entry[40]; /* LFN entry contains up to 13 UTF16 characters, up to 40 bytes including null term are necessary when encoded using UTF8 */ char fs_file[SFILENAME_SIZE + 1]; uint32_t prev_cluster = *prev_cluster_ptr; uint32_t dirname = 0; error_code = MFS_NO_ERROR; entries_per_sector = drive_ptr->ENTRIES_PER_SECTOR; current_cluster = *start_cluster_ptr; current_index = *dir_index_ptr; found = FALSE; lfn_flag = FALSE; /* If the name is a LFN, it will be treated differently */ if ( file_ptr && *file_ptr && !MFS_Dirname_valid(file_ptr) ) { lfn_flag = TRUE; lfn_len = _strnlen(file_ptr, PATHNAME_SIZE); /* Set pointer just behind the end of the filename */ lfn_ptr = file_ptr + lfn_len; maybe = TRUE; found_lfn = FALSE; /* We also need special treatement for a directory name */ if ( attribute == (ATTR_EXCLUSIVE | MFS_ATTR_DIR_NAME) ) { attribute = MFS_ATTR_LFN; dirname = 1; } } else if ( file_ptr && *file_ptr ) { MFS_Expand_dotfile(file_ptr, fs_file); } /* ** Search in all clusters within this directory */ do { /* ** Search in all sectors within this cluster */ for ( k = (uint16_t) INDEX_TO_SECTOR(current_index); ((current_cluster == 0) || (k < drive_ptr->BPB.SECTORS_PER_CLUSTER)) && found == FALSE && current_cluster != CLUSTER_EOF; k++ ) { dir_entry_ptr = MFS_Read_directory_sector(drive_ptr,current_cluster, k, &error_code); if ( dir_entry_ptr == NULL ) { break; } /* ** Search in all entries within this sector */ for ( i = (uint16_t) INDEX_TO_OFFSET(current_index), dir_entry_ptr += i ; i < entries_per_sector && found == FALSE; i++ ) { if ( *dir_entry_ptr->NAME == '\0' ) /* if NEVER USED entry */ { if ( file_ptr ) /* If not NULL */ { if ( !*file_ptr ) /* but "" */ { /* we found it */ found = TRUE; break; } } return(NULL); /* Anyway, stop here-never used entry */ /* if the entry is relevant at all */ } else if ( (unsigned char) *dir_entry_ptr->NAME == MFS_DEL_FILE ) { /* If DELETED */ if ( file_ptr ) /* If not NULL */ { if ( !*file_ptr ) /* but "" */ { found = TRUE; /* we found it */ break; } } } else /* If REGULAR ENTRY */ { if ( file_ptr == NULL || *file_ptr ) { if ( MFS_Attribute_match(mqx_dtohc(dir_entry_ptr->ATTRIBUTE), attribute) == TRUE ) { if ( !file_ptr ) { found = TRUE; break; } else if ( lfn_flag ) /* Searching for a long name */ { if ( found_lfn ) { found = TRUE; break; } if ( !MFS_Attribute_match(mqx_dtohc(dir_entry_ptr->ATTRIBUTE), MFS_ATTR_LFN) ) { maybe = TRUE; /* Reset maybe */ dir_entry_ptr++; current_index++; continue; /* Not an LFN entry, skip it */ } if ( !maybe ) { dir_entry_ptr++; current_index++; continue; } int chunk_len; chunk_len = MFS_lfn_extract((MFS_LNAME_ENTRY_PTR)dir_entry_ptr, lfn_entry); if(lfn_ptr >= (file_ptr + chunk_len)) { lfn_ptr -= chunk_len; if ( strncmp(lfn_entry, lfn_ptr, chunk_len) ) { lfn_ptr = file_ptr + lfn_len; /* reset ptr */ maybe = FALSE; dir_entry_ptr++; current_index++; continue; /* Strings don't match */ } if ( lfn_ptr == file_ptr ) { found_lfn = TRUE; if ( dirname ) { attribute = ATTR_EXCLUSIVE | MFS_ATTR_DIR_NAME; } } } else { maybe = FALSE; lfn_ptr = file_ptr + lfn_len; /* reset ptr */ } } else /* Searching for a short name */ { found = MFS_Wildcard_match(fs_file, dir_entry_ptr->NAME); } } else { if ( lfn_flag ) { attribute = MFS_ATTR_LFN; lfn_ptr = file_ptr + lfn_len; /* reset ptr */ maybe = TRUE; found_lfn = FALSE; } } } } if ( found == FALSE ) { dir_entry_ptr++; current_index++; } } } if ( found == FALSE ) { error_code = MFS_Increment_dir_index(drive_ptr, ¤t_cluster, ¤t_index, &prev_cluster); if ( error_code ) { break; } } } while ( found == FALSE && dir_entry_ptr && current_cluster != CLUSTER_EOF && current_cluster != CLUSTER_INVALID ); if ( found == FALSE ) { dir_entry_ptr = NULL; } else { *start_cluster_ptr = current_cluster; *prev_cluster_ptr = prev_cluster; *dir_index_ptr = current_index; } if ( error_ptr ) { *error_ptr = error_code; } return(dir_entry_ptr); }
/*FUNCTION*------------------------------------------------------------------- * * Function Name : MFS_Find_directory * Returned Value : starting_cluster of the specified directory * Comments : Search through the file structure to find the specified * directory. Will search either from the current directory or from the * root directory. Returns the starting cluster number of the specified * directory. If the specified directory cannot be found, then * CLUSTER_INVALID is returned. * *END*---------------------------------------------------------------------*/ uint32_t MFS_Find_directory ( MFS_DRIVE_STRUCT_PTR drive_ptr, /*[IN] drive context */ char *path_ptr, /*[IN] specific directory to search for */ uint32_t first_cluster /*[IN] start searching in this cluster, used for a relative search*/ ) { MFS_DIR_ENTRY_PTR dir_entry_ptr; char *directory; uint32_t current_cluster; uint32_t dir_index; _mfs_error error_code; bool flag; uint32_t prev_cluster = CLUSTER_INVALID; unsigned char attribute; if ( MFS_alloc_path(&directory)!= MFS_NO_ERROR ) { return( CLUSTER_INVALID ); } if ( *path_ptr == '\\' || *path_ptr == '/' ) { current_cluster = ROOT_CLUSTER(drive_ptr); path_ptr++; } else { current_cluster = first_cluster; } while ( path_ptr ) { if ( *path_ptr ) { path_ptr = MFS_Parse_next_filename(path_ptr, directory); if ( !MFS_lfn_dirname_valid(directory) ) { current_cluster = CLUSTER_INVALID; break; } flag = FALSE; if ( current_cluster == 0 ) flag = TRUE; if ( drive_ptr->FAT_TYPE == MFS_FAT32 ) { if ( current_cluster == drive_ptr->BPB32.ROOT_CLUSTER ) { flag = TRUE; } } if ( flag ) { /* ** Special treatment for '.' and '..' in root directory */ dir_index = MFS_Is_dot_directory(directory); if ( dir_index == 1 ) { /* Return the value of the root cluster */ MFS_free_path(directory); return ROOT_CLUSTER(drive_ptr); } else if ( dir_index == 2 ) { MFS_free_path(directory); return(CLUSTER_INVALID); } } dir_index = 0; dir_entry_ptr = MFS_Find_directory_entry( drive_ptr, directory, ¤t_cluster, &dir_index, &prev_cluster, (~ATTR_EXCLUSIVE), &error_code); if ( dir_entry_ptr == NULL ) { current_cluster = CLUSTER_INVALID; break; } else { attribute = mqx_dtohc(dir_entry_ptr->ATTRIBUTE); if ( attribute & MFS_ATTR_DIR_NAME ) { current_cluster = clustoh(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER); if ( current_cluster == 0 && drive_ptr->FAT_TYPE == MFS_FAT32 ) { current_cluster = drive_ptr->BPB32.ROOT_CLUSTER; } } else { // Found an entry, but it is not a directory MFS_free_path(directory); return(CLUSTER_INVALID); } } } else { break; } } MFS_free_path(directory); return(current_cluster); }
_mfs_error MFS_Remove_subdir ( MFS_DRIVE_STRUCT_PTR drive_ptr, char *pathname /*[IN] pathname of the directory to be removed */ ) { _mfs_error error_code, saved_error = 0; uint32_t dir_cluster, parent_cluster, dir_index; MFS_DIR_ENTRY_PTR dir_entry_ptr; uint32_t prev_cluster= CLUSTER_INVALID; uint32_t parent_prev_cluster= CLUSTER_INVALID; if ( (pathname == NULL) || (*pathname == '\0') ) { return MFS_INVALID_PARAMETER; } error_code = MFS_lock_dos_disk( drive_ptr ); if ( error_code != MFS_NO_ERROR ) { return error_code; } dir_entry_ptr = MFS_Find_entry_on_disk (drive_ptr, pathname, &error_code, &parent_cluster, &dir_index, &parent_prev_cluster); if ( dir_entry_ptr ) { if ( mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & MFS_ATTR_DIR_NAME ) { dir_cluster = clustoh(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER); if ( dir_cluster != drive_ptr->CUR_DIR_CLUSTER ) { dir_index = 2; /* Skip over '.' and '..' */ dir_entry_ptr = MFS_Find_directory_entry (drive_ptr, NULL, &dir_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY, &error_code); if ( dir_entry_ptr == NULL && !error_code ) { dir_index = 0; dir_entry_ptr = MFS_Find_entry_on_disk (drive_ptr, pathname, &error_code, &parent_cluster, &dir_index, &parent_prev_cluster); if ( dir_entry_ptr ) { *dir_entry_ptr->NAME = MFS_DEL_FILE; drive_ptr->DIR_SECTOR_DIRTY = TRUE; error_code = MFS_remove_lfn_entries(drive_ptr, parent_cluster, dir_index, parent_prev_cluster); if ( !error_code ) { saved_error = MFS_Release_chain(drive_ptr, dir_cluster); } } } else if ( dir_entry_ptr != NULL && !error_code ) { error_code = MFS_FILE_EXISTS; } } else { error_code = MFS_ATTEMPT_TO_REMOVE_CURRENT_DIR; } } else { error_code = MFS_WRITE_FAULT; } } else { error_code = MFS_PATH_NOT_FOUND; } MFS_unlock(drive_ptr,TRUE); if ( saved_error == MFS_LOST_CHAIN && error_code == MFS_NO_ERROR ) { error_code = saved_error; } return(error_code); }
void *MFS_Open_file ( MFS_DRIVE_STRUCT_PTR drive_ptr, char *pathname, /*[IN] directory and filename of the file to be opened */ unsigned char access, /*[IN] type of access required: read, write or read/write*/ uint32_t *error_ptr /*[IN/OUT] error code is written to this address */ ) { MFS_DIR_ENTRY_PTR dir_entry_ptr; MFS_HANDLE_PTR handle,open_handle; uint32_t dir_cluster, dir_index; _mfs_error error_code; uint32_t prev_cluster= CLUSTER_INVALID; if ( (pathname == NULL) || (*pathname == '\0') ) { if ( error_ptr != NULL ) { *error_ptr = MFS_INVALID_PARAMETER; } return NULL; } error_code = MFS_lock_dos_disk( drive_ptr ); if ( error_code != MFS_NO_ERROR ) { if ( error_ptr != NULL ) { *error_ptr = error_code; } return NULL; } handle = NULL; dir_entry_ptr = MFS_Find_entry_on_disk(drive_ptr, pathname, &error_code, &dir_cluster, &dir_index, &prev_cluster); if ( error_code == MFS_NO_ERROR ) { if ( mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & (MFS_ATTR_DIR_NAME | MFS_ATTR_VOLUME_NAME) ) { error_code = MFS_WRITE_FAULT; } else if ( (mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & MFS_ATTR_READ_ONLY) && ((access == MFS_ACCESS_WRITE_ONLY) || (access == MFS_ACCESS_READ_WRITE)) ) { error_code = MFS_ACCESS_DENIED; } else { // Check to see if the file is already opened open_handle = MFS_Find_handle(drive_ptr, dir_cluster, dir_index); if (open_handle) { // If we are opening to write, the file can't already be opened. if ((access == MFS_ACCESS_WRITE_ONLY) || (access == MFS_ACCESS_READ_WRITE)) { error_code = MFS_SHARING_VIOLATION; } // And if we the file is already opened, it can't be opened to write. // Note that if it is opened for write, it will be the only instance on the list if ((handle->ACCESS == MFS_ACCESS_WRITE_ONLY) || (handle->ACCESS == MFS_ACCESS_READ_WRITE)) { error_code = MFS_SHARING_VIOLATION; } } if (error_code == MFS_NO_ERROR) { handle = MFS_Get_handle(drive_ptr,dir_entry_ptr); if ( handle != NULL ) { handle->ACCESS = access; handle->CURRENT_CLUSTER = 0; handle->PREVIOUS_CLUSTER = 0; handle->DIR_CLUSTER = dir_cluster; handle->DIR_INDEX = dir_index; } else { error_code = MFS_INSUFFICIENT_MEMORY; } } } } MFS_unlock(drive_ptr,FALSE); if ( error_ptr ) { *error_ptr = error_code; } return((void *) handle); }
/*! * \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; }