Guys, I have a f_seek function I'm working on. I have listed the code below. In the test (cluster size equals 4096) I open the file and the pointer points to the first data element. I then f_seek, 5000 offset from the current position. The f_seek function then correctly detects that a cluster move to the next position is required. So it removes 4096 and moves to the next cluster. It then offsets by 904, also correct. BUT!
When it goes to do the following to the pointer, it is incorrectly offset. I hope I've explained this has best I can.
c_printf("\n\r[r]Offset %i", iOffset); c_printf("\n\r[m]Current Ptr Addr! %x", file->data_file->data_cache); // update_data_cache data pointer to new location file->data_file->data_cache += iOffset; c_printf("\n\r[m]New Ptr Addr! %x", file->data_file->data_cache);
Also, if instead I do an offset of 3000, i.e less than the cluster size the math works? I did suspects a failure to allocate memory or something but I've checked everything.
FULL CODE
/* * fat32_seek.c * * Created on: 8 Apr 2022 * Author: wmjen */ /* * exfat_seek.c * * Created on: 8 Dec 2021 * Author: wmjen */ #include <stdio.h> #include <stdlib.h> #include "fat32_seek.h" #include "clusters_fat32.h" #include "fat32.h" #include "../../rtx/system_malloc.h" #include "../hal/file_system_driver.h" #include "../../tx/user_interface/console.h" /** * * @param file - file stream pointer * @return new cluster number * * Add data cluster to data cluster chain */ static unsigned int data_table_remove_cluster(FILEX * file){ // remove this directory struct data_file_entry * dir = file->data_file->data_file_table->cluster_chain->prev; if( file->data_file->data_file_table->nr == 1){ file->data_file->data_file_table->nr = 0; } else { file->data_file->data_file_table->nr--; if(file->data_file->data_file_table->cluster_chain == dir){ file->data_file->data_file_table->cluster_chain = dir->next; } dir->prev->next = dir->next; dir->next->prev = dir->prev; } // free memory rtos_free(dir); return(1); } void fat32_close_indexing(FILEX * file){ while(file->data_file->data_file_table->nr != 0){ data_table_remove_cluster(file); } } /** * * @param file stream pointer * @return ignore */ static unsigned int data_table_insert_cluster(FILEX * file){ // allocate memory for new link node struct data_file_entry * dir = rtos_malloc(sizeof(struct data_file_entry)); // log cluster number dir->cluster_nr = file->data_file->data_cluster_nr; // add to double link list if( file->data_file->data_file_table->nr == 0){ // setup ptrs for quick access file->data_file->data_file_table->start = dir; file->data_file->data_file_table->end = dir; file->data_file->data_file_table->position = dir; file->data_file->data_file_table->cluster_chain = dir; dir->next = dir; dir->prev = dir; file->data_file->data_file_table->nr = 1; } else{ file->data_file->data_file_table->nr++; dir->next = file->data_file->data_file_table->cluster_chain; dir->prev = file->data_file->data_file_table->cluster_chain->prev; file->data_file->data_file_table->cluster_chain->prev->next = dir; file->data_file->data_file_table->cluster_chain->prev = dir; file->data_file->data_file_table->end = dir; } return 1; } /** * * @param file stream pointer * @return last cluster number */ void fat32_build_file(FILEX * file){ unsigned int cluster, temp; cluster = get_cluster_marker(file, file->data_file->data_cluster_nr); temp = file->data_file->data_cluster_nr; // traverse the cluster chain until we reach a end msarker, i.e 0xffffffff while(1){ // insert cluster on to link list data_table_insert_cluster(file); // quit when we reach end cluster if(cluster >= 0x0ffffff8) break; // setup new cluster file->data_file->data_cluster_nr = cluster; cluster = get_cluster_marker(file, file->data_file->data_cluster_nr); } // restore pointer to first cluster file->data_file->data_cluster_nr = temp; } static char load_first_cluster_index(FILEX * file){ if(file->data_file->data_file_table->nr > 0){ // obtain start cluster unsigned int cluster_nr = file->data_file->data_file_table->start->cluster_nr; // point position to start file->data_file->data_file_table->position = file->data_file->data_file_table->start; // obtain relative hardware address unsigned int hardware_addr = cluster_address(file, cluster_nr); // setup clusters file->data_file->data_cluster_nr = cluster_nr; file->data_file->data_cluster_addr = hardware_addr; // reset data read ptr file->data_file->data_cache = file->data_file->free_data; return cluster_nr; } return 0; } static char load_end_cluster_index(FILEX * file){ if(file->data_file->data_file_table->nr > 0){ // obtain end position cluster unsigned int cluster_nr = file->data_file->data_file_table->end->cluster_nr; // set position to the end file->data_file->data_file_table->position = file->data_file->data_file_table->end; // obtain relative hardware address unsigned int hardware_addr = cluster_address(file, cluster_nr); // setup clusters file->data_file->data_cluster_nr = cluster_nr; file->data_file->data_cluster_addr = hardware_addr; // reset data read ptr file->data_file->data_cache = file->data_file->free_data; return cluster_nr; } return 0; } static char load_next_cluster_index(FILEX * file){ if(file->data_file->data_file_table->nr > 0){ // obtain next cluster unsigned int cluster_nr = file->data_file->data_file_table->position->next->cluster_nr; // set position to next cluster position file->data_file->data_file_table->position = file->data_file->data_file_table->position->next; // obtain relative hardware address unsigned int hardware_addr = cluster_address(file, cluster_nr); // setup clusters file->data_file->data_cluster_nr = cluster_nr; file->data_file->data_cluster_addr = hardware_addr; // reset data read ptr file->data_file->data_cache = file->data_file->free_data; return cluster_nr; } return 0; } static char load_prev_cluster_index(FILEX * file){ if(file->data_file->data_file_table->nr > 0){ // obtain previous cluster unsigned int cluster_nr = file->data_file->data_file_table->position->prev->cluster_nr; // set position to previous cluster file->data_file->data_file_table->position = file->data_file->data_file_table->position->prev; // obtain relative hardware address unsigned int hardware_addr = cluster_address(file, cluster_nr); file->data_file->data_cluster_nr = cluster_nr; file->data_file->data_cluster_addr = hardware_addr; // reset data read ptr file->data_file->data_cache = file->data_file->free_data; return cluster_nr; } return 0; } /** * * @param file - file Stream * @param iOffset - offset from location specified * @param iWhence - SET, CUR, END locations */ unsigned long long fat32_seek(FILEX * file, int iOffset, int iWhence ){ int cluster_count; char update_data_cache = 0; /** * Handle SEEK, i.e. move forward/backwards through the file!!! */ if(iWhence == FF_SEEK_SET){ // configure f_tell file->data_file->f_tell_index = iOffset; // load first cluster if we are not already pointing to it if(file->data_file->data_file_table->start != file->data_file->data_file_table->position){ // load first cluster load_first_cluster_index(file); // update data cache update_data_cache = 1; } // if offset is greater than zero if(iOffset > 0){ // if need to load one or more clusters due to the offset being greater than // the cluster size if(iOffset >= fat_cluster_size(file)){ // number of clusters to traverse cluster_count = iOffset / fat_cluster_size(file); for(int i = 0; i < cluster_count; i++){ // move to next cluster position load_next_cluster_index(file); } // update data cache update_data_cache = 1; } // calculate offset required, mod iOffset = iOffset % fat_cluster_size(file); // update_data_cache ptr file->data_file->data_cache = file->data_file->free_data + iOffset; } else file->data_file->data_cache = file->data_file->free_data; } else if(iWhence == FF_SEEK_END){ // go to end cluster position if we are elsewhere if(file->data_file->data_file_table->end != file->data_file->data_file_table->position){ // load end cluster load_end_cluster_index(file); // update data cache update_data_cache = 1; // go to last element in file file->data_file->data_cache = file->data_file->free_data + (file->data_file->file_size % (fat_cluster_size(file) - 1)); } // if offset requires processing then begin by calculating the offset in clusters required if(iOffset < 0){ // f_tell information file->data_file->f_tell_index = file->data_file->file_size - iOffset; // make positive iOffset = iOffset * -1; // if boundary violated then handle if(((file->data_file->data_cache - file->data_file->free_data) - iOffset) < 0){ // subtract boundary iOffset -= (file->data_file->data_cache - file->data_file->free_data); // point to previous cluster load_prev_cluster_index(file); // go to last element in file file->data_file->data_cache = file->data_file->free_data + (fat_cluster_size(file) - 1); // update data cache update_data_cache = 1; } // if offset is now still greater than a cluster size then handle if(iOffset >= fat_cluster_size(file)){ // update data cache update_data_cache = 1; // number of clusters to travel cluster_count = iOffset / fat_cluster_size(file); // begin travelling backwards for(int i = 0; i < cluster_count; i++) load_prev_cluster_index(file); // go to last element in file file->data_file->data_cache = file->data_file->free_data + (fat_cluster_size(file) - 1); } // calculate offset modula operator iOffset = iOffset % fat_cluster_size(file); // update_data_cache ptr file->data_file->data_cache -= iOffset; } } else if(iWhence == FF_SEEK_CUR){ // handle overflow if(iOffset > 0){ // f_tell information file->data_file->f_tell_index += iOffset; // handle overflow first - boundary if(((file->data_file->data_cache - file->data_file->free_data) + iOffset) >= fat_cluster_size(file)){ // calculate new offset by removing the offset required to reach next cluster iOffset -= (fat_cluster_size(file) - (file->data_file->data_cache - file->data_file->free_data)); // update data cache update_data_cache = 1; // load next cluster load_next_cluster_index(file); } // if offset is still passing a cluster boundary if(iOffset >= fat_cluster_size(file)){ // update data cache update_data_cache = 1; // number of clusters to traverse cluster_count = iOffset / fat_cluster_size(file); // traverse clusters for(int i = 0; i < cluster_count; i++) load_next_cluster_index(file); } //calculate offset remaining iOffset = iOffset % fat_cluster_size(file); c_printf("\n\r[r]Offset %i", iOffset); c_printf("\n\r[m]Current Ptr Addr! %x", file->data_file->data_cache); // update_data_cache data pointer to new location file->data_file->data_cache += iOffset; c_printf("\n\r[m]New Ptr Addr! %x", file->data_file->data_cache); } else{ // make positive iOffset = iOffset * -1; // f_tell information file->data_file->f_tell_index -= iOffset; // will a boundary be violated? if(((file->data_file->data_cache - file->data_file->free_data) - iOffset) < 0){ // remove boundary iOffset -= (file->data_file->data_cache - file->data_file->free_data); // update data cache update_data_cache = 1; // move to previous cluster load_prev_cluster_index(file); // go to last element in file file->data_file->data_cache = file->data_file->free_data + (fat_cluster_size(file) - 1); } // offset still violates the boundary if(iOffset >= fat_cluster_size(file)){ // update data cache update_data_cache = 1; // number of clusters to travel cluster_count = iOffset / fat_cluster_size(file); // begin travelling backwards for(int i = 0; i < cluster_count; i++) load_prev_cluster_index(file); // go to last element in file file->data_file->data_cache = file->data_file->free_data + (fat_cluster_size(file) - 1); } // calculate offset mod iOffset = iOffset % fat_cluster_size(file); // set the new data pointer offset // update_data_cache memory file->data_file->data_cache -= iOffset; } } // update_data_cache data cache with new cluster if(update_data_cache) dma_hardware_read(1, file->data_file->data_cluster_addr, fat_sectors_per_cluster(file), file->data_file->free_data, 0); return -1; }