//------------------------------------------------------------------------------ // return the size in bytes of a cluster chain uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const { uint32_t s = 0; do { if (!fatGet(cluster, &cluster)) return false; s += 512UL << clusterSizeShift_; } while (!isEOC(cluster)); *size = s; return true; }
//------------------------------------------------------------------------------ // free a cluster chain uint8_t SdVolume::freeChain(uint32_t cluster) { // clear free cluster location allocSearchStart_ = 2; do { uint32_t next; if (!fatGet(cluster, &next)) return false; // free cluster if (!fatPut(cluster, 0)) return false; cluster = next; } while (!isEOC(cluster)); return true; }
//------------------------------------------------------------------------------ bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) { uint32_t find = current ? current : m_allocSearchStart; uint32_t start = find; while (1) { find++; // If at end of FAT go to beginning of FAT. if (find > m_lastCluster) { find = 2; } uint32_t f; int8_t fg = fatGet(find, &f); if (fg < 0) { DBG_FAIL_MACRO; goto fail; } if (fg && f == 0) { break; } if (find == start) { // Can't find space checked all clusters. DBG_FAIL_MACRO; goto fail; } } // mark end of chain if (!fatPutEOC(find)) { DBG_FAIL_MACRO; goto fail; } if (current) { // link clusters if (!fatPut(current, find)) { DBG_FAIL_MACRO; goto fail; } } else { // Remember place for search start. m_allocSearchStart = find; } updateFreeClusterCount(-1); *next = find; return true; fail: return false; }
//------------------------------------------------------------------------------ // find a contiguous group of clusters uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { // start of group uint32_t bgnCluster; // flag to save place to start next search uint8_t setStart; // set search start cluster if (*curCluster) { // try to make file contiguous bgnCluster = *curCluster + 1; // don't save new start location setStart = false; } else { // start at likely place for free cluster bgnCluster = allocSearchStart_; // save next search start if one cluster setStart = 1 == count; } // end of group uint32_t endCluster = bgnCluster; // last cluster of FAT uint32_t fatEnd = clusterCount_ + 1; // search the FAT for free clusters for (uint32_t n = 0;; n++, endCluster++) { // can't find space checked all clusters if (n >= clusterCount_) return false; // past end - start from beginning of FAT if (endCluster > fatEnd) { bgnCluster = endCluster = 2; } uint32_t f; if (!fatGet(endCluster, &f)) return false; if (f != 0) { // cluster in use try next cluster as bgnCluster bgnCluster = endCluster + 1; } else if ((endCluster - bgnCluster + 1) == count) { // done - found space break; } } // mark end of chain if (!fatPutEOC(endCluster)) return false; // link clusters while (endCluster > bgnCluster) { if (!fatPut(endCluster - 1, endCluster)) return false; endCluster--; } if (*curCluster != 0) { // connect chains if (!fatPut(*curCluster, bgnCluster)) return false; } // return first cluster number to caller *curCluster = bgnCluster; // remember possible next free cluster if (setStart) allocSearchStart_ = bgnCluster + 1; return true; }
//------------------------------------------------------------------------------ // find a contiguous group of clusters bool FatVolume::allocContiguous(uint32_t count, uint32_t* firstCluster) { // flag to save place to start next search bool setStart = true; // start of group uint32_t bgnCluster; // end of group uint32_t endCluster; // Start at cluster after last allocated cluster. uint32_t startCluster = m_allocSearchStart; endCluster = bgnCluster = startCluster + 1; // search the FAT for free clusters while (1) { // If past end - start from beginning of FAT. if (endCluster > m_lastCluster) { bgnCluster = endCluster = 2; } uint32_t f; int8_t fg = fatGet(endCluster, &f); if (fg < 0) { DBG_FAIL_MACRO; goto fail; } if (f || fg == 0) { // cluster in use try next cluster as bgnCluster bgnCluster = endCluster + 1; // don't update search start if unallocated clusters before endCluster. if (bgnCluster != endCluster) { setStart = false; } } else if ((endCluster - bgnCluster + 1) == count) { // done - found space break; } // Can't find space if all clusters checked. if (startCluster == endCluster) { DBG_FAIL_MACRO; goto fail; } endCluster++; } // remember possible next free cluster if (setStart) { m_allocSearchStart = endCluster + 1; } // mark end of chain if (!fatPutEOC(endCluster)) { DBG_FAIL_MACRO; goto fail; } // link clusters while (endCluster > bgnCluster) { if (!fatPut(endCluster - 1, endCluster)) { DBG_FAIL_MACRO; goto fail; } endCluster--; } // Maintain count of free clusters. updateFreeClusterCount(-count); // return first cluster number to caller *firstCluster = bgnCluster; return true; fail: return false; }