embkernel
 All Classes Functions Variables Typedefs Groups Pages
FsPartition.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "FsPartition.hpp"
7 #include "FsDrive.hpp"
8 #include "LibEndian.hpp"
9 
10 FsPartition::FsPartition(class FsDrive* drive, int indexOnDrive) {
11  mIsValid = false;
12  mDrive = drive;
13  mIndexOnDrive = indexOnDrive;
14 }
15 
16 uint32_t FsPartition::getRootClusterLba() {
17  return getClusterBeginLba(mRootDirFirstCluster);
18 }
19 
20 uint32_t FsPartition::getFatSectorLba(uint32_t cluster) {
21  return mFatBeginLba + (cluster >> 7);
22 }
23 
24 uint32_t FsPartition::getFatSectorIndex(uint32_t cluster) {
25  return (cluster & 0x7F);
26 }
27 
28 uint32_t FsPartition::getClusterBeginLba(uint32_t cluster) {
29  return mClusterBeginLba + (cluster - 2) * mSectorsPerCluster;
30 }
31 
32 uint32_t FsPartition::getClusterFromLba(uint32_t lba) {
33  return ((lba - mClusterBeginLba) / mSectorsPerCluster) + 2;
34 }
35 
37 //
39 FsDefs::RESULT FsPartition::initFromBootSector(FsDefs::BOOT_SECTOR* bootSector, uint32_t partitionBeginLba) {
40  uint16_t rootEntCnt = LibEndian::leToHw(bootSector->rootEntCnt);
41  uint16_t bytsPerSec = LibEndian::leToHw(bootSector->bytsPerSec);
42 
43  uint32_t rootDirSectors = ((rootEntCnt * 32) + (bytsPerSec - 1)) / bytsPerSec;
44 
45  //Get fat type
46  uint32_t fatSz = LibEndian::leToHw(bootSector->fatSz16);
47  if (!fatSz) {
48  fatSz = LibEndian::leToHw(bootSector->type.fat32.fatSz32);
49  }
50  uint32_t totSectors = LibEndian::leToHw(bootSector->totSec16);
51  if (!totSectors) {
52  totSectors = LibEndian::leToHw(bootSector->totSec32);
53  }
54 
55  uint16_t rsvdSecCnt = LibEndian::leToHw(bootSector->rsvdSecCnt);
56  uint32_t dataSectorsCount = totSectors - rsvdSecCnt + (bootSector->numFats * fatSz) + rootDirSectors;
57  uint32_t clustersCount = dataSectorsCount / bootSector->secPerClus;
58  uint32_t fatBeginLba = LibEndian::leToHw(mFatBeginLba);
59  uint32_t bigSectorsPerFat = LibEndian::leToHw(bootSector->fatSz16);
60  mRootDirFirstCluster = 2;
61  if (clustersCount < 4085) {
62  mFatType = FsPartition::FAT12;
63  }
64  else if (clustersCount < 65525) {
65  mFatType = FsPartition::FAT16;
66  }
67  else {
68  mInfoSectorLba = fatBeginLba + LibEndian::leToHw(bootSector->type.fat32.fsInfo);
69  mBackupBootSectorLba = fatBeginLba + LibEndian::leToHw(bootSector->type.fat32.bkBootSec);
70  bigSectorsPerFat = LibEndian::leToHw(bootSector->type.fat32.fatSz32);
71  mRootDirFirstCluster = LibEndian::leToHw(bootSector->type.fat32.rootClus);
72  mFatType = FsPartition::FAT32;
73  }
74 
75  mFatBeginLba = partitionBeginLba + rsvdSecCnt;
76  mClusterBeginLba = mFatBeginLba + ((uint32_t) bootSector->numFats * bigSectorsPerFat);
77  mSectorsPerCluster = bootSector->secPerClus;
78  mClustersCount = clustersCount;
79  mNumFats = bootSector->numFats;
80 
81  mInfoFreeClusterCount = 0xFFFFFFFF;
82  mInfoNextFreeCluster = 0xFFFFFFFF;
83 
84  mIsValid = true;
85 
86  if (mFatType == FsPartition::FAT32) {
87  if (!mDrive->readBlocks((FsDefs::SECTOR*) bootSector, mInfoSectorLba, 1)) {
88  return FsDefs::RES_DISK_ERROR;
89  }
90  FsDefs::FS_INFO* fsInfo = (FsDefs::FS_INFO*) bootSector;
91  mInfoFreeClusterCount = LibEndian::leToHw(fsInfo->freeCount);
92  mInfoNextFreeCluster = LibEndian::leToHw(fsInfo->nextFree);
93  }
94  return FsDefs::RES_SUCCESS;
95 }
96 
97 FsDefs::RESULT FsPartition::getNextBlockLba(FsDefs::SECTOR* sector, uint32_t* lba) {
98  if ((++*lba - mClusterBeginLba) % mSectorsPerCluster) {
99  return FsDefs::RES_SUCCESS;
100  }
101  else { //Follow chain
102  uint32_t currentCluster = getClusterFromLba(*lba - 1);
103  //Read next cluster from FAT
104  if (!mDrive->readBlocks(sector, getFatSectorLba(currentCluster), 1)) {
105  *lba -= 1;
106  return FsDefs::RES_DISK_ERROR;
107  }
108  uint32_t nextCluster = sector->dwords[FsPartition::getFatSectorIndex(currentCluster)];
109  if (nextCluster >= 0xFFFFFFF8 || nextCluster == 0) {
110  *lba -= 1;
111  return FsDefs::RES_EOF;
112  }
113  else {
114  *lba = getClusterBeginLba(nextCluster);
115  return FsDefs::RES_SUCCESS;
116  }
117  }
118  return FsDefs::RES_SUCCESS;
119 }
120 
121 FsDefs::RESULT FsPartition::getNextFreeCluster(FsDefs::SECTOR* sector, uint32_t* cluster) {
122  if (mInfoSectorLba) {
123  *cluster = mInfoNextFreeCluster;
124  }
125  else {
126  *cluster = mRootDirFirstCluster;
127  }
128  //TODO remove
129  *cluster = mRootDirFirstCluster;
130  if (!mDrive->readBlocks(sector, getFatSectorLba(*cluster), 1)) {
131  return FsDefs::RES_DISK_ERROR;
132  }
133  for (unsigned int i = 0; i < mClustersCount; i++) {
134  if (sector->dwords[FsPartition::getFatSectorIndex(*cluster)] == 0) {
135  mInfoNextFreeCluster = *cluster;
136  return FsDefs::RES_SUCCESS;
137  }
138  (*cluster)++;
139  if (*cluster >= mClustersCount) {
140  *cluster = mRootDirFirstCluster;
141  }
142  if ((FsPartition::getFatSectorIndex(*cluster)) == 0) {
143  if (!mDrive->readBlocks(sector, getFatSectorLba(*cluster), 1)) {
144  return FsDefs::RES_DISK_ERROR;
145  }
146  }
147  }
148  return FsDefs::RES_DISK_FULL;
149 }
150 
151 FsDefs::RESULT FsPartition::appendFreeCluster(FsDefs::SECTOR* sector, uint32_t* cluster) {
152  uint32_t freeCluster;
153  FsDefs::RESULT result = getNextFreeCluster(sector, &freeCluster);
154  if (result != FsDefs::RES_SUCCESS) {
155  return result;
156  }
157  result = setFatValue(sector, *cluster, freeCluster);
158  if (result != FsDefs::RES_SUCCESS) {
159  return result;
160  }
161  result = setFatValue(sector, freeCluster, FsDefs::FAT_LAST_CLUSTER);
162  if (result != FsDefs::RES_SUCCESS) {
163  return result;
164  }
165  if (mInfoFreeClusterCount > 0) {
166  mInfoFreeClusterCount--;
167  }
168  updateInfo(sector);
169  *cluster = freeCluster;
170  return FsDefs::RES_SUCCESS;
171 }
172 
173 FsDefs::RESULT FsPartition::setFatValue(FsDefs::SECTOR* sector, uint32_t cluster, uint32_t value) {
174  if (!mDrive->readBlocks(sector, getFatSectorLba(cluster), 1)) {
175  return FsDefs::RES_DISK_ERROR;
176  }
177  sector->dwords[FsPartition::getFatSectorIndex(cluster)] = LibEndian::hwToLe(value);
178  return writeFatSector(sector, cluster);
179 }
180 
181 FsDefs::RESULT FsPartition::writeFatSector(FsDefs::SECTOR* sector, uint32_t cluster) {
182  for (uint32_t i = 0, lba = getFatSectorLba(cluster); i < mNumFats; i++) {
183  if (!mDrive->writeBlocks(sector, lba, 1)) {
184  return FsDefs::RES_DISK_ERROR;
185  }
186  lba += lba + (i * mClustersCount >> 7);
187  }
188  return FsDefs::RES_SUCCESS;
189 }
190 
191 FsDefs::RESULT FsPartition::freeClusterChain(FsDefs::SECTOR* sector, uint32_t cluster) {
192  if ((cluster == FsDefs::FAT_FREE_CLUSTER) || (cluster == 0)) {
193  return FsDefs::RES_SUCCESS;
194  }
195 
196  uint32_t lba = getFatSectorLba(cluster);
197  if (!mDrive->readBlocks(sector, lba, 1)) {
198  return FsDefs::RES_DISK_ERROR;
199  }
200 
201  while (true) {
202  uint16_t index = getFatSectorIndex(cluster);
203  uint32_t nextCluster = sector->dwords[index];
204  mInfoFreeClusterCount++;
205  if ((nextCluster > FsDefs::FAT_MAX_CLUSTER_VALUE) || (nextCluster == 0)) {
206  sector->dwords[index] = FsDefs::FAT_FREE_CLUSTER;
207  FsDefs::RESULT result = writeFatSector(sector, cluster);
208  if (result != FsDefs::RES_SUCCESS) {
209  return result;
210  }
211  break;
212  }
213 
214  sector->dwords[index] = FsDefs::FAT_FREE_CLUSTER;
215  uint32_t nextLba = getFatSectorLba(nextCluster);
216  if (nextLba != lba) {
217  FsDefs::RESULT result = writeFatSector(sector, cluster);
218  if (result != FsDefs::RES_SUCCESS) {
219  return result;
220  }
221  if (!mDrive->readBlocks(sector, lba, 1)) {
222  return FsDefs::RES_DISK_ERROR;
223  }
224  lba = nextLba;
225  }
226  cluster = nextCluster;
227  }
228 
229  updateInfo(sector);
230  return FsDefs::RES_SUCCESS;
231 }
232 
233 FsDefs::RESULT FsPartition::updateInfo(FsDefs::SECTOR* sector) {
234  if (mInfoSectorLba == 0) {
235  return FsDefs::RES_SUCCESS;
236  }
237  if (!mDrive->readBlocks(sector, mInfoSectorLba, 1)) {
238  return FsDefs::RES_DISK_ERROR;
239  }
240  FsDefs::FS_INFO* fsInfo = (FsDefs::FS_INFO*) sector;
241  fsInfo->nextFree = LibEndian::hwToLe(mInfoNextFreeCluster);
242  fsInfo->freeCount = LibEndian::hwToLe(mInfoFreeClusterCount);
243  if (!mDrive->writeBlocks(sector, mInfoSectorLba, 1)) {
244  return FsDefs::RES_DISK_ERROR;
245  }
246  return FsDefs::RES_SUCCESS;
247 }
248 
249 bool FsPartition::readBlocks(FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
250  return mDrive->readBlocks(buffer, blockNumber, blockCount);
251 }
252 
253 bool FsPartition::writeBlocks(const FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
254  return mDrive->writeBlocks(buffer, blockNumber, blockCount);
255 }
256 
257 void FsPartition::lock() {
258  mDrive->lock();
259 }
260 
261 void FsPartition::unlock() {
262  mDrive->unlock();
263 }
264