The Pedigree Project  0.1
FatFilesystem.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "FatFilesystem.h"
21 #include "FatDirectory.h"
22 #include "FatFile.h"
23 #include "FatSymlink.h"
24 #include "fat.h"
25 #include "modules/Module.h"
26 #include "modules/system/vfs/Directory.h"
27 #include "modules/system/vfs/File.h"
28 #include "modules/system/vfs/VFS.h"
29 #include "pedigree/kernel/Log.h"
30 #include "pedigree/kernel/machine/Disk.h"
31 #include "pedigree/kernel/process/Scheduler.h"
32 #include "pedigree/kernel/processor/types.h"
33 #include "pedigree/kernel/syscallError.h"
34 #include "pedigree/kernel/utilities/StaticString.h"
35 #include "pedigree/kernel/utilities/String.h"
36 #include "pedigree/kernel/utilities/Tree.h"
38 #include "pedigree/kernel/utilities/utility.h"
39 
40 class Filesystem;
41 
42 // helper functions
43 
44 static bool isPowerOf2(uint32_t n)
45 {
46  uint8_t log;
47 
48  for (log = 0; log < 16; log++)
49  {
50  if (n & 1)
51  {
52  n >>= 1;
53  return (n != 0) ? false : true;
54  }
55  n >>= 1;
56  }
57  return false;
58 }
59 
60 FatFilesystem::FatFilesystem()
61  : m_Superblock(), m_Superblock16(), m_Superblock32(), m_FsInfo(),
62  m_Type(FAT12), m_DataAreaStart(0), m_RootDirCount(0), m_FatSector(0),
63  m_RootDir(), m_BlockSize(0), m_pFatCache(0), m_FatLock(), m_pRoot(0),
64  m_FatCache(), m_FreeClusterHint()
65 {
66 }
67 
68 FatFilesystem::~FatFilesystem()
69 {
70  if (m_pRoot)
71  delete m_pRoot;
72  if (m_pFatCache)
73  delete[] m_pFatCache;
74 }
75 
77 {
78  m_pDisk = pDisk;
79 
80  // Attempt to read the superblock.
81  uint8_t *buffer = reinterpret_cast<uint8_t *>(m_pDisk->read(0));
82 
83  MemoryCopy(
84  reinterpret_cast<void *>(&m_Superblock),
85  reinterpret_cast<void *>(buffer), sizeof(Superblock));
86 
88  String devName;
89  pDisk->getName(devName);
90 
91  /* check for EITHER a near jmp, or a jmp and a nop */
92  if (m_Superblock.BS_jmpBoot[0] != 0xE9)
93  {
94  if (!(m_Superblock.BS_jmpBoot[0] == 0xEB &&
95  m_Superblock.BS_jmpBoot[2] == 0x90))
96  {
97  ERROR(
98  "FAT: Superblock not found on device "
99  << devName << " [" << m_Superblock.BS_jmpBoot[0] << ", "
100  << m_Superblock.BS_jmpBoot[2] << "]");
101  return false;
102  }
103  }
104 
107  // SecPerClus must be a power of 2
108  if (!isPowerOf2(m_Superblock.BPB_SecPerClus))
109  {
110  ERROR(
111  "FAT: SecPerClus not a power of 2 (" << m_Superblock.BPB_SecPerClus
112  << ")");
113  return false;
114  }
115 
116  // and there must be at least 1 FAT, and at most 2
117  if (m_Superblock.BPB_NumFATs < 1 || m_Superblock.BPB_NumFATs > 2)
118  {
119  ERROR(
120  "FAT: Too many (or too few) FATs (" << m_Superblock.BPB_NumFATs
121  << ")");
122  return false;
123  }
124 
127  // load the 12/16/32 additional info structures (only one is actually VALID,
128  // but both are loaded nonetheless)
129  MemoryCopy(
130  reinterpret_cast<void *>(&m_Superblock16),
131  reinterpret_cast<void *>(buffer + 36), sizeof(Superblock16));
132  MemoryCopy(
133  reinterpret_cast<void *>(&m_Superblock32),
134  reinterpret_cast<void *>(buffer + 36), sizeof(Superblock32));
135 
136  // number of root directory sectors
137  if (!m_Superblock.BPB_BytsPerSec) // we sanity check the value, because we
138  // divide by this later
139  {
140  return false;
141  }
142  uint32_t rootDirSectors = ((m_Superblock.BPB_RootEntCnt * 32) +
143  (m_Superblock.BPB_BytsPerSec - 1)) /
144  m_Superblock.BPB_BytsPerSec;
145 
146  // determine the size of the FAT
147  uint32_t fatSz = (m_Superblock.BPB_FATSz16) ? m_Superblock.BPB_FATSz16 :
148  m_Superblock32.BPB_FATSz32;
149 
150  // find the first data sector
151  uint32_t firstDataSector = m_Superblock.BPB_RsvdSecCnt +
152  (m_Superblock.BPB_NumFATs * fatSz) +
153  rootDirSectors;
154 
155  // determine the number of data sectors, so we can determine FAT type
156  uint32_t totDataSec = 0, totSec = (m_Superblock.BPB_TotSec16) ?
157  m_Superblock.BPB_TotSec16 :
158  m_Superblock.BPB_TotSec32;
159  totDataSec = totSec - firstDataSector;
160 
161  if (!m_Superblock
162  .BPB_SecPerClus) // again, sanity checking due to division by this
163  {
164  ERROR("FAT: SecPerClus is zero!");
165  return false;
166  }
167  uint32_t clusterCount = totDataSec / m_Superblock.BPB_SecPerClus;
168 
169  // TODO: magic numbers here, perhaps #define MAXCLUS_{12|16|32} would work
170  // better for readability
171  if (clusterCount < 4085)
172  {
173  m_Type = FAT12;
174  NOTICE("FAT: Device " << devName << " is type FAT12");
175  }
176  else if (clusterCount < 65525)
177  {
178  m_Type = FAT16;
179  NOTICE("FAT: Device " << devName << " is type FAT16");
180  }
181  else
182  {
183  m_Type = FAT32;
184  NOTICE("FAT: Device " << devName << " is type FAT32");
185  }
186 
187  switch (m_Type)
188  {
189  case FAT12:
190  case FAT16:
191 
192  m_RootDir.sector = m_Superblock.BPB_RsvdSecCnt +
193  (m_Superblock.BPB_NumFATs * fatSz);
194 
195  break;
196 
197  case FAT32:
198 
199  m_RootDir.cluster = m_Superblock32.BPB_RootClus;
200 
201  break;
202  }
203 
204  // fill the filesystem data
205  m_DataAreaStart = firstDataSector;
206  m_RootDirCount = rootDirSectors;
207  m_BlockSize = m_Superblock.BPB_SecPerClus * m_Superblock.BPB_BytsPerSec;
208 
209  // read in the FAT32 FSInfo structure
210  if (m_Type == FAT32)
211  {
212  uint32_t sec = m_Superblock32.BPB_FsInfo;
213  readSectorBlock(sec, 512, reinterpret_cast<uintptr_t>(&m_FsInfo));
214  }
215 
216  // Save the start sector of the FAT now
217  m_FatSector = m_Superblock.BPB_RsvdSecCnt;
218 
219  // Setup the free cluster hint for non-FAT32 volumes
220  m_FreeClusterHint = 2;
221 
222  // Define the root directory early
223  getRoot();
224 
225  return true;
226 }
227 
228 Filesystem *FatFilesystem::probe(Disk *pDisk)
229 {
230  FatFilesystem *pFs = new FatFilesystem();
231  if (!pFs->initialise(pDisk))
232  {
233  delete pFs;
234  return 0;
235  }
236  else
237  {
238  return pFs;
239  }
240 }
241 
242 void FatFilesystem::loadRootDir()
243 {
244  if (m_pRoot)
245  {
246  return;
247  }
248 
249  // needs to return a file referring to the root directory
250  uint32_t cluster = 0;
251  if (m_Type == FAT32)
252  cluster = m_RootDir.cluster;
253 
254  FatFileInfo info;
255  info.creationTime = info.modifiedTime = info.accessedTime = 0;
256 
257  m_pRoot = new FatDirectory(String(""), cluster, this, 0, info);
258 }
259 
261 {
262  return m_pRoot;
263 }
264 
265 void FatFilesystem::cacheVolumeLabel()
266 {
267  // The root directory (typically) contains the volume label, with a specific
268  // flag In my experience, it's always the first entry, and it's always
269  // there. Even so, we want to cater to unusual formats.
270  //
271  // In order to do so we check the entire root directory.
272 
273  uint32_t sz = m_BlockSize;
274 
275  uint32_t clus = 0;
276  if (m_Type == FAT32)
277  clus = m_RootDir.cluster;
278 
279  String volid;
280 
281  uint8_t *buffer = reinterpret_cast<uint8_t *>(readDirectoryPortion(clus));
282 
283  size_t i;
284  bool endOfDir = false;
285  while (true)
286  {
287  for (i = 0; i < sz; i += sizeof(Dir))
288  {
289  Dir *ent = reinterpret_cast<Dir *>(&buffer[i]);
290 
291  if (ent->DIR_Name[0] == 0)
292  {
293  endOfDir = true;
294  break;
295  }
296 
297  if (ent->DIR_Attr & ATTR_VOLUME_ID)
298  {
299  volid = convertFilenameFrom(
300  String(reinterpret_cast<const char *>(ent->DIR_Name)));
301  delete[] buffer;
302  m_VolumeLabel = volid;
303  return;
304  }
305  }
306 
307  if (endOfDir)
308  break;
309 
310  if (clus == 0 && m_Type != FAT32)
311  break; // not found
312 
313  // find the next cluster in the chain, if this is the end, break, if
314  // not, continue
315  clus = getClusterEntry(clus);
316  if (clus == 0)
317  break; // something broke!
318 
319  if (isEof(clus))
320  break;
321 
322  // continue by reading in this cluster
323  readCluster(clus, reinterpret_cast<uintptr_t>(buffer));
324  }
325 
326  delete[] buffer;
327 
328  // none found, do a default
329  NormalStaticString str;
330  str += "no-volume-label@";
331  str.append(reinterpret_cast<uintptr_t>(this), 16);
332  m_VolumeLabel.assign(str, str.length(), true);
333 }
334 
336 {
337  return m_VolumeLabel;
338 }
339 
341 
342 uint64_t FatFilesystem::read(
343  File *pFile, uint64_t location, uint64_t size, uintptr_t buffer,
344  bool bCanBlock)
345 {
346  // Sanity check.
347  if (pFile->isDirectory())
348  return 0;
349 
350  // the inode of the file is the first cluster
351  uint32_t clus = pFile->getInode();
352  if (clus == 0)
353  return 0; // can't do it
354 
355  // validity checking
356  if (location >= pFile->getSize())
357  {
358  WARNING(
359  "FAT: Attempting to read past the EOF [loc="
360  << location << ", sz=" << size << ", fsz=" << pFile->getSize()
361  << "]");
362  return 0;
363  }
364 
365  uint64_t endOffset = location + size;
366  uint64_t finalSize = size;
367  if (endOffset > pFile->getSize())
368  {
369  finalSize = pFile->getSize() - location;
370 
371  // overflow (location > size) or zero bytes required (location == size)
372  if ((finalSize == 0) || (finalSize > pFile->getSize()))
373  {
374  WARNING("FAT: location + size > EOF");
375  return 0;
376  }
377  }
378 
379  // finalSize holds the total amount of data to read, now find the cluster
380  // and sector offsets
381  uint32_t clusOffset =
382  location / (m_Superblock.BPB_SecPerClus * m_Superblock.BPB_BytsPerSec);
383  uint32_t firstOffset =
384  location % (m_Superblock.BPB_SecPerClus *
385  m_Superblock.BPB_BytsPerSec); // the offset within the
386  // cluster specified above to
387  // start reading from
388 
389  // tracking info
390 
391  uint64_t bytesRead = 0;
392  uint64_t currOffset = firstOffset;
393  while (clusOffset)
394  {
395  clus = getClusterEntry(clus);
396  if (clus == 0 || isEof(clus))
397  {
398  WARNING(
399  "FAT: CLUSTER FAIL - "
400  << clus << ", cluster offset = " << clusOffset
401  << "."); // <-- This is where the installer + lodisk is
402  // failing.
403  WARNING(" -> file: " << pFile->getFullPath());
404  WARNING(" -> size: " << pFile->getSize());
405  return 0; // can't do it
406  }
407  clusOffset--;
408  }
409 
410  // buffers
411  uint8_t *tmpBuffer = new uint8_t[m_BlockSize];
412  uint8_t *destBuffer = reinterpret_cast<uint8_t *>(buffer);
413 
414  // main read loop
415  while (true)
416  {
417  // read in the entire cluster
418  readCluster(clus, reinterpret_cast<uintptr_t>(tmpBuffer));
419 
420  // How many bytes should we copy?
421  size_t bytesToCopy = finalSize - bytesRead;
422  if (bytesToCopy > m_BlockSize)
423  {
424  bytesToCopy = m_BlockSize;
425  }
426 
427  // Perform the copy.
428  MemoryCopy(&destBuffer[bytesRead], &tmpBuffer[currOffset], bytesToCopy);
429  bytesRead += bytesToCopy;
430 
431  // Done?
432  if (bytesRead == finalSize)
433  {
434  delete[] tmpBuffer;
435  return bytesRead;
436  }
437 
438  // end of cluster, set the offset back to zero
439  currOffset = 0;
440 
441  // grab the next cluster, check for EOF
442  clus = getClusterEntry(clus);
443  if (clus == 0)
444  break; // something broke!
445 
446  if (isEof(clus))
447  break;
448  }
449 
450  delete[] tmpBuffer;
451 
452  // if we reach here, something's gone wrong
453  WARNING("FAT: read returning zero... Something's not right.");
454  return 0;
455 }
456 
458 
459 uint32_t FatFilesystem::findFreeCluster(bool bLock)
460 {
461  size_t j;
462  uint32_t clus;
463  uint32_t totalSectors = m_Superblock.BPB_TotSec32;
464  if (totalSectors == 0)
465  {
466  if (m_Type != FAT32)
467  totalSectors = m_Superblock.BPB_TotSec16;
468  else
469  {
470  return 0;
471  }
472  }
473 
474  uint32_t mask = m_Type == FAT32 ? 0x0FFFFFFF : 0xFFFF;
475 
476  for (j = (m_Type == FAT32 ? m_FsInfo.FSI_NxtFree : m_FreeClusterHint);
477  j < (totalSectors / m_Superblock.BPB_SecPerClus); j++)
478  {
479  clus = getClusterEntry(j, false);
480  if ((clus & mask) == 0)
481  {
483  setClusterEntry(
484  j, eofValue(),
485  false); // default to it being EOF - ie, pin the cluster
486 
487  // All done!
488  m_FreeClusterHint = j + 1;
489  return j;
490  }
491  }
492 
493  FATAL("findFreeCluster returning zero!");
494  return 0;
495 }
496 
498 
499 uint64_t FatFilesystem::write(
500  File *pFile, uint64_t location, uint64_t size, uintptr_t buffer,
501  bool bCanBlock)
502 {
503 #ifdef SUPERDEBUG
504  NOTICE("FatFilesystem::write(" << pFile->getName() << ")");
505 #endif
506 
507  // test whether the entire Filesystem is read-only.
508  if (m_bReadOnly)
509  {
510 #ifdef SUPERDEBUG
511  NOTICE("FAT: readonly filesystem");
512 #endif
513  SYSCALL_ERROR(ReadOnlyFilesystem);
514  return 0;
515  }
516 
517  // we do so much work with the FAT here that locking is a necessity
518  // LockGuard<Mutex> guard(m_FatLock);
519 
520  int64_t fileSizeChange = 0;
521  if ((location + size) > pFile->getSize())
522  fileSizeChange = (location + size) - pFile->getSize();
523 
524  uint32_t firstClus = pFile->getInode();
525 
526  if (firstClus == 0)
527  {
528  // find a free cluster for this file
529  uint32_t freeClus = findFreeCluster();
530  if (freeClus == 0)
531  {
532  SYSCALL_ERROR(NoSpaceLeftOnDevice);
533  return 0;
534  }
535 
536  // set EOF
537  setClusterEntry(freeClus, eofValue(), false);
538  firstClus = freeClus;
539 
540  // write into the directory entry, and into the File itself
541  pFile->setInode(freeClus);
542  setCluster(pFile, freeClus);
543  }
544 
545  uint32_t clusSize =
546  m_Superblock.BPB_SecPerClus * m_Superblock.BPB_BytsPerSec;
547  uint32_t finalOffset = location + size;
548  uint32_t offsetSector = location / m_Superblock.BPB_BytsPerSec;
549  uint32_t clus = 0;
550 
551  // does the file currently have enough clusters to allow us to write without
552  // stopping?
553  int i = clusSize;
554  int j = pFile->getSize() / i;
555  if (pFile->getSize() % i)
556  j++; // extra cluster (integer division)
557  if (j == 0)
558  j = 1; // always one cluster
559 
560  uint32_t finalCluster = j * i;
561  uint32_t numExtraBytes = 0;
562 
563  // if the final offset is past what we already have in the cluster chain,
564  // fill in the blanks
565  if (finalOffset > finalCluster)
566  {
567  numExtraBytes = finalOffset - finalCluster;
568 
569  j = numExtraBytes / i;
570  if (numExtraBytes % i)
571  j++;
572 
573  clus = firstClus;
574 
575  uint32_t lastClus = clus;
576  while (!isEof(clus))
577  {
578  lastClus = clus;
579  clus = getClusterEntry(clus, false);
580  }
581 
582  uint32_t prev = 0;
583  for (i = 0; i < j; i++)
584  {
585  prev = lastClus;
586  lastClus = findFreeCluster();
587  if (!lastClus)
588  {
589  SYSCALL_ERROR(NoSpaceLeftOnDevice);
590  return 0;
591  }
592 
593  setClusterEntry(prev, lastClus, false);
594  }
595 
596  setClusterEntry(lastClus, eofValue(), false);
597  }
598 
599  uint64_t finalSize = size;
600 
601  // finalSize holds the total amount of data to read, now find the cluster
602  // and sector offsets
603  uint32_t clusOffset =
604  offsetSector /
605  m_Superblock.BPB_SecPerClus; // location / (m_Superblock.BPB_SecPerClus
606  // * m_Superblock.BPB_BytsPerSec);
607  uint32_t firstOffset =
608  location % (m_Superblock.BPB_SecPerClus *
609  m_Superblock.BPB_BytsPerSec); // the offset within the
610  // cluster specified above to
611  // start reading from
612 
613  // tracking info
614 
615  uint64_t bytesWritten = 0;
616  uint64_t currOffset = firstOffset;
617  clus = firstClus;
618  for (uint32_t z = 0; z < clusOffset; z++)
619  {
620  clus = getClusterEntry(clus, false);
621  if (clus == 0 || isEof(clus))
622  return 0;
623  }
624 
625  // buffers
626  uint8_t *tmpBuffer = new uint8_t[m_BlockSize];
627  uint8_t *srcBuffer = reinterpret_cast<uint8_t *>(buffer);
628 
629 #ifdef SUPERDEBUG
630  NOTICE("FAT bytesWritten=" << bytesWritten << " finalSize=" << finalSize);
631 #endif
632 
633  // main write loop
634  while (bytesWritten < finalSize)
635  {
636  // Read in this cluster - we're about to modify it.
637  readCluster(clus, reinterpret_cast<uintptr_t>(tmpBuffer));
638 
639  // Update based on our buffer.
640  size_t len = m_BlockSize;
641  if ((bytesWritten + len) > finalSize)
642  len = finalSize - bytesWritten;
643 
644  // The first write may be in the middle of a cluster, hence currOffset's
645  // use.
646  MemoryCopy(&tmpBuffer[currOffset], &srcBuffer[bytesWritten], len);
647  bytesWritten += len;
648 
649 // Write updated cluster to disk.
650 #ifdef SUPERDEBUG
651  NOTICE("FAT write - clus=" << clus);
652  NOTICE("FAT write - offset=" << getSectorNumber(clus) * 512);
653 #endif
654  writeCluster(clus, reinterpret_cast<uintptr_t>(tmpBuffer));
655 
656  // No longer at the beginning of the write - reset cluster offset to
657  // zero.
658  currOffset = 0;
659 
660  // Grab next cluster ready for further writing.
661  clus = getClusterEntry(clus, false);
662  if (clus == 0)
663  break;
664 
665  if (isEof(clus))
666  {
667  if (bytesWritten < finalSize)
668  FATAL(
669  "EOF before written - still "
670  << Dec << (finalSize - bytesWritten) << Hex
671  << " bytes unwritten!!");
672  break;
673  }
674  }
675 
676  // Update the size on disk, if needed.
677  if (fileSizeChange != 0)
678  {
679 #ifdef SUPERDEBUG
680  NOTICE(
681  "FAT Updating file size on disk change=" << Dec << fileSizeChange
682  << Hex << "!");
683 #endif
684  updateFileSize(pFile, fileSizeChange);
685  pFile->setSize(pFile->getSize() + fileSizeChange);
686  }
687 
688  delete[] tmpBuffer;
689 
690  return bytesWritten;
691 }
692 
694 
695 void FatFilesystem::updateFileSize(File *pFile, int64_t sizeChange)
696 {
697  // don't bother reading the directory if there's no actual change
698  if (sizeChange == 0)
699  return;
700 
701  uint32_t dirClus = static_cast<FatFile *>(pFile)->getDirCluster();
702  uint32_t dirOffset = static_cast<FatFile *>(pFile)->getDirOffset();
703 
704  Dir *p = getDirectoryEntry(dirClus, dirOffset);
705  if (!p)
706  return;
707  p->DIR_FileSize += sizeChange;
708  writeDirectoryEntry(p, dirClus, dirOffset);
709 
710  delete p;
711 }
712 
713 void FatFilesystem::setCluster(File *pFile, uint32_t clus)
714 {
715  // don't bother reading and writing if the cluster is zero
716  if (clus == 0)
717  return;
718 
719  uint32_t dirClus = static_cast<FatFile *>(pFile)->getDirCluster();
720  uint32_t dirOffset = static_cast<FatFile *>(pFile)->getDirOffset();
721 
722  Dir *p = getDirectoryEntry(dirClus, dirOffset);
723  if (!p)
724  return;
725  p->DIR_FstClusLO = clus & 0xFFFF;
726  p->DIR_FstClusHI = (clus >> 16) & 0xFFFF;
727  writeDirectoryEntry(p, dirClus, dirOffset);
728 
729  delete p;
730 }
731 
732 void *FatFilesystem::readDirectoryPortion(uint32_t clus) const
733 {
734  uint32_t dirClus = clus;
735  uint8_t *dirBuffer = 0;
736 
737  if (dirClus == 0)
738  {
739  if (m_Type != FAT32)
740  {
741  uint32_t sec = m_RootDir.sector;
742  uint32_t sz = m_RootDirCount * m_Superblock.BPB_BytsPerSec;
743 
744  dirBuffer = new uint8_t[sz];
745  readSectorBlock(sec, sz, reinterpret_cast<uintptr_t>(dirBuffer));
746  }
747  else
748  return 0;
749  }
750  else
751  {
752  dirBuffer = new uint8_t[m_BlockSize];
753  readCluster(dirClus, reinterpret_cast<uintptr_t>(dirBuffer));
754  }
755 
756  return reinterpret_cast<void *>(dirBuffer);
757 }
758 
759 void FatFilesystem::writeDirectoryPortion(uint32_t clus, void *p)
760 {
761  if (!p)
762  return;
763  bool secMethod = false;
764  uint32_t sz = m_BlockSize;
765  uint32_t sec = m_RootDir.sector;
766  if (clus == 0)
767  {
768  if (m_Type != FAT32)
769  {
770  sz = m_RootDirCount * m_Superblock.BPB_BytsPerSec;
771  secMethod = true;
772  }
773  else
774  return;
775  }
776 
777  if (secMethod)
778  writeSectorBlock(sec, sz, reinterpret_cast<uintptr_t>(p));
779  else
780  writeCluster(clus, reinterpret_cast<uintptr_t>(p));
781 }
782 
783 Dir *FatFilesystem::getDirectoryEntry(uint32_t clus, uint32_t offset) const
784 {
785  uint8_t *dirBuffer =
786  reinterpret_cast<uint8_t *>(readDirectoryPortion(clus));
787  if (!dirBuffer)
788  return 0;
789 
790  Dir *ent = reinterpret_cast<Dir *>(&dirBuffer[offset]);
791  Dir *ret = new Dir;
792  MemoryCopy(ret, ent, sizeof(Dir));
793 
794  delete[] dirBuffer;
795 
796  return ret;
797 }
798 
800  Dir *dir, uint32_t clus, uint32_t offset)
801 {
802  // don't bother reading and writing if the cluster is zero or if there's no
803  // entry to write
804  if (dir == 0)
805  return;
806 
807  uint8_t *dirBuffer =
808  reinterpret_cast<uint8_t *>(readDirectoryPortion(clus));
809  if (!dirBuffer)
810  return;
811 
812  Dir *ent = reinterpret_cast<Dir *>(&dirBuffer[offset]);
813  MemoryCopy(ent, dir, sizeof(Dir));
814 
815  writeDirectoryPortion(clus, dirBuffer);
816 
817  delete[] dirBuffer;
818 }
819 
820 void FatFilesystem::fileAttributeChanged(File *pFile)
821 {
822 }
823 
824 void FatFilesystem::cacheDirectoryContents(File *pFile)
825 {
826 }
827 
828 bool FatFilesystem::readCluster(uint32_t block, uintptr_t buffer) const
829 {
830  block = getSectorNumber(block);
831  readSectorBlock(block, m_BlockSize, buffer);
832  return true;
833 }
834 
835 bool FatFilesystem::readSectorBlock(uint32_t sec, size_t size, uintptr_t buffer) const
836 {
837  if (!buffer)
838  {
839  return false;
840  }
841 
842  size_t off = 0;
843  while (size)
844  {
845  size_t sz = (size > 512) ? 512 : size;
846  uintptr_t buff = m_pDisk->read(
847  (static_cast<uint64_t>(m_Superblock.BPB_BytsPerSec) *
848  static_cast<uint64_t>(sec)) +
849  off);
850  if (!buff)
851  return false;
852  MemoryCopy(
853  reinterpret_cast<void *>(buffer), reinterpret_cast<void *>(buff),
854  sz);
855  buffer += sz;
856  size -= sz;
857  off += sz;
858  }
859  return true;
860 }
861 
862 bool FatFilesystem::writeCluster(uint32_t block, uintptr_t buffer)
863 {
864  block = getSectorNumber(block);
865  writeSectorBlock(block, m_BlockSize, buffer);
866  return true;
867 }
868 
870  uint32_t sec, size_t size, uintptr_t buffer)
871 {
872  if (!buffer)
873  {
874  return false;
875  }
876 
877  size_t off = 0;
878  while (size)
879  {
880  size_t sz = (size > 4096) ? 4096 : size;
881  uintptr_t buff = m_pDisk->read(
882  static_cast<uint64_t>(m_Superblock.BPB_BytsPerSec) *
883  static_cast<uint64_t>(sec) +
884  off);
885  MemoryCopy(
886  reinterpret_cast<void *>(buff), reinterpret_cast<void *>(buffer),
887  sz);
888  m_pDisk->write(
889  static_cast<uint64_t>(m_Superblock.BPB_BytsPerSec) *
890  static_cast<uint64_t>(sec) +
891  off);
892  buffer += sz;
893  size -= sz;
894  off += sz;
895  }
896  return true;
897 }
898 
899 uint32_t FatFilesystem::getSectorNumber(uint32_t cluster) const
900 {
901  return ((cluster - 2) * m_Superblock.BPB_SecPerClus) + m_DataAreaStart;
902 }
903 
904 uint32_t FatFilesystem::getClusterEntry(uint32_t cluster, bool bLock)
905 {
906  uint32_t fatOffset = 0;
907  switch (m_Type)
908  {
909  case FAT12:
910  fatOffset = cluster + (cluster / 2);
911  break;
912 
913  case FAT16:
914  fatOffset = cluster * 2;
915  break;
916 
917  case FAT32:
918  fatOffset = cluster * 4;
919  break;
920  }
921 
922  // uint8_t *fatBlocks = new uint8_t[m_Superblock.BPB_BytsPerSec * 2];
923 
924  // Reading from the FAT - critical section
925  while (!m_FatLock.enter())
926  {
928  }
929  uint32_t *fatBlocks = reinterpret_cast<uint32_t *>(
930  m_FatCache.lookup(fatOffset / m_Superblock.BPB_BytsPerSec));
931  m_FatLock.leave();
932 
933  if (fatBlocks && (m_Type == FAT12))
934  {
935  FATAL("Oooer missus, work needed heres");
936  // fatBlocks = reinterpret_cast<uint8_t*>(m_FatCache.lookup((fatOffset /
937  // m_Superblock.BPB_BytsPerSec) + 1, fatBlocks +
938  // m_Superblock.BPB_BytsPerSec));
939  }
940  if (!fatBlocks)
941  {
942  m_FatLock.acquire();
943 
944  fatBlocks = new uint32_t
945  [((m_Superblock.BPB_BytsPerSec * 2) / sizeof(uint32_t)) + 1];
946  if (!readSectorBlock(
947  m_FatSector + (fatOffset / m_Superblock.BPB_BytsPerSec),
948  m_Superblock.BPB_BytsPerSec * 2,
949  reinterpret_cast<uintptr_t>(fatBlocks)))
950  {
951  ERROR("FAT: getClusterEntry: reading from the FAT failed");
952  delete[] fatBlocks;
953  m_FatLock.release();
954  return 0;
955  }
956 
957  m_FatCache.insert(
958  fatOffset / m_Superblock.BPB_BytsPerSec,
959  reinterpret_cast<uintptr_t>(fatBlocks));
960  m_FatCache.insert(
961  (fatOffset / m_Superblock.BPB_BytsPerSec) + 1,
962  reinterpret_cast<uintptr_t>(
963  adjust_pointer(fatBlocks, m_Superblock.BPB_BytsPerSec)));
964  NOTICE("FAT Cache now has " << m_FatCache.count() << " sectors.");
965 
966  m_FatLock.release();
967  }
968 
969  // read from cache
970  fatOffset %= m_Superblock.BPB_BytsPerSec;
971  fatOffset /= sizeof(uint32_t);
972  uint32_t fatEntry = fatBlocks[fatOffset];
973 
975  // delete [] fatBlocks;
976 
977  // calculate
978  uint32_t ret = 0;
979  switch (m_Type)
980  {
981  case FAT12:
982  ret = fatEntry;
983 
984  // FAT12 entries are 1.5 bytes
985  if (cluster & 0x1)
986  ret >>= 4;
987  else
988  ret &= 0x0FFF;
989  ret &= 0xFFFF;
990 
991  break;
992 
993  case FAT16:
994 
995  ret = fatEntry;
996  ret &= 0xFFFF;
997 
998  break;
999 
1000  case FAT32:
1001 
1002  ret = fatEntry & 0x0FFFFFFF;
1003 
1004  break;
1005  }
1006 
1007  return ret;
1008 }
1009 
1010 uint32_t
1011 FatFilesystem::setClusterEntry(uint32_t cluster, uint32_t value, bool bLock)
1012 {
1013  if (cluster == 0)
1014  {
1015  FATAL(
1016  "setClusterEntry called with invalid arguments - " << cluster << "/"
1017  << value << "!");
1018  return 0;
1019  }
1020 
1021  uint32_t fatOffset = 0;
1022  switch (m_Type)
1023  {
1024  case FAT12:
1025  fatOffset = cluster + (cluster / 2);
1026  break;
1027 
1028  case FAT16:
1029  fatOffset = cluster * 2;
1030  break;
1031 
1032  case FAT32:
1033  fatOffset = cluster * 4;
1034  break;
1035  }
1036 
1037  uint32_t ent = getClusterEntry(cluster, bLock);
1038 
1039  // uint8_t *fatBlocks = new uint8_t[m_Superblock.BPB_BytsPerSec * 2];
1040 
1041  uint32_t *fatBlocks = reinterpret_cast<uint32_t *>(
1042  m_FatCache.lookup(fatOffset / m_Superblock.BPB_BytsPerSec));
1043  if (fatBlocks && (m_Type == FAT12))
1044  {
1045  FATAL("Ooer missus, work needed here");
1046  // fatBlocks =
1047  // reinterpret_cast<uint8_t*>(m_FatCache.lookup((fatOffset /
1048  // m_Superblock.BPB_BytsPerSec) + 1, fatBlocks +
1049  // m_Superblock.BPB_BytsPerSec));
1050  }
1051  if (!fatBlocks)
1052  {
1053  ERROR("FAT: setClusterEntry: getClusterEntry didn't read sectors from "
1054  "cache properly?");
1055  // delete [] fatBlocks;
1056  return 0;
1057  }
1058 
1059  uint32_t oldOffset = fatOffset;
1060  fatOffset %= m_Superblock.BPB_BytsPerSec;
1061  fatOffset /= sizeof(uint32_t);
1062 
1063  uint32_t origEnt = ent;
1064  uint32_t setEnt = value;
1065 
1066  // Calculate and write back into the cache
1067  switch (m_Type)
1068  {
1069  case FAT12:
1070 
1071  if (cluster & 0x1)
1072  {
1073  value <<= 4;
1074  origEnt &= 0x000F;
1075  }
1076  else
1077  {
1078  value &= 0x0FFF;
1079  origEnt &= 0xF000;
1080  }
1081 
1082  setEnt = origEnt | value;
1083 
1084  fatBlocks[fatOffset] = setEnt;
1085 
1086  break;
1087 
1088  case FAT16:
1089 
1090  setEnt = value;
1091 
1092  fatBlocks[fatOffset] = setEnt;
1093 
1094  break;
1095 
1096  case FAT32:
1097 
1098  value &= 0x0FFFFFFF;
1099  setEnt = origEnt & 0xF0000000;
1100  setEnt |= value;
1101 
1102  fatBlocks[fatOffset] = setEnt;
1103 
1104  break;
1105  }
1106 
1107  uint32_t fatSector =
1108  m_FatSector + (oldOffset / m_Superblock.BPB_BytsPerSec);
1109 
1110  // Grab the FAT lock - we're updating it now
1111  m_FatLock.acquire();
1112 
1113  // Write back to the FAT
1114  writeSectorBlock(
1115  fatSector, m_Superblock.BPB_BytsPerSec * 2,
1116  reinterpret_cast<uintptr_t>(fatBlocks));
1117 
1118  // Write back to the cache
1119  m_FatCache.insert(
1120  oldOffset / m_Superblock.BPB_BytsPerSec,
1121  reinterpret_cast<uintptr_t>(fatBlocks));
1122  if (m_Type == FAT12)
1123  m_FatCache.insert(
1124  (oldOffset / m_Superblock.BPB_BytsPerSec) + 1,
1125  reinterpret_cast<uintptr_t>(
1126  fatBlocks + m_Superblock.BPB_BytsPerSec));
1127 
1128  // All done with the update
1129  m_FatLock.release();
1130 
1132 // delete [] fatBlocks;
1133 
1134 // We're pedantic and as such we check things, but only if debugging
1135 #if defined(DEBUGGER) && defined(ADDITIONAL_CHECKS)
1136  uint32_t val = getClusterEntry(cluster, false);
1137  if (val != value)
1138  FATAL(
1139  "setClusterEntry has failed on cluster " << cluster << ": " << val
1140  << "/" << value << ".");
1141 #endif
1142 
1143  return setEnt;
1144 }
1145 
1147 {
1148  // Special dot & dotdot handling. Because periods are eaten by the
1149  // algorithm, we need to ensure that the dot and dotdot entries are returned
1150  // with only padding.
1151  if (!StringCompare(static_cast<const char *>(fn), ".") ||
1152  !StringCompare(static_cast<const char *>(fn), ".."))
1153  {
1154  NormalStaticString ret;
1155  ret = fn;
1156  ret.pad(11);
1157  return String(static_cast<const char *>(ret));
1158  }
1159 
1160  // Strip the filename of any whitespace that might be dangling off the end.
1161  fn.rstrip();
1162 
1163  NormalStaticString filename, ext;
1164 
1165  // Initial generation loop.
1166  size_t lastPeriod = ~0UL;
1167  for (size_t i = 0; i < fn.length(); ++i)
1168  {
1169  // Valid character?
1170  if (fn[i] == ' ' || fn[i] == '"' || fn[i] == '/' || fn[i] == '\\' ||
1171  fn[i] == '[' || fn[i] == ']' || fn[i] == ':' || fn[i] == ';' ||
1172  fn[i] == '=' || fn[i] == ',')
1173  continue; // Illegal for SFN.
1174  else if (fn[i] == '.')
1175  {
1176  if ((i + 1) >= fn.length())
1177  {
1178  // Stripped input but whitespace follows. Ignore and terminate
1179  // loop.
1180  break;
1181  }
1182  lastPeriod = i;
1183  }
1184  else
1185  {
1186  filename += toUpper(fn[i]);
1187  }
1188  }
1189 
1190  // Truncate filename if the filename portion is > 8 characters long
1191  if (lastPeriod > 8)
1192  {
1193  filename.truncate(6);
1194  filename += "~1";
1195  }
1197  // Or is the filename now longer than the distance to the last period?
1198  else if (lastPeriod != ~0UL)
1199  {
1200  filename.truncate(lastPeriod);
1201  }
1202 
1203  // Is the filename now empty?
1204  if (!filename.length())
1205  {
1206  // Yes, dotfile (eg, .vimrc)
1207  ++lastPeriod;
1208 
1209  // .vimrc -> VIMRC~1
1210  for (size_t i = 0; i < 6; ++i)
1211  {
1212  if ((lastPeriod + i) >= fn.length())
1213  break;
1214  filename += toUpper(fn[lastPeriod + i]);
1215  }
1216 
1217  // Add tail, pad, and return.
1218  filename += "~1";
1219  filename.pad(11);
1220  return String(static_cast<const char *>(filename));
1221  }
1222 
1223  // Pull the extension out, truncated to 3 characters, and skipping the full
1224  // stoop.
1225  for (size_t i = 1; i < 4; ++i)
1226  {
1227  if ((lastPeriod + i) >= fn.length())
1228  break;
1229  ext += toUpper(fn[lastPeriod + i]);
1230  }
1231 
1232  // Pad as necessary.
1233  filename.pad(8);
1234  ext.pad(3);
1235 
1236  // Merge the two strings and return!
1237  filename.append(ext);
1238  filename += '\0';
1239  return String(static_cast<const char *>(filename));
1240 }
1241 
1243 {
1244  static NormalStaticString ret;
1245  ret.clear();
1246 
1247  size_t i;
1248  for (i = 0; i < 8; i++)
1249  {
1250  if (i >= filename.length())
1251  break;
1252  if (filename[i] != ' ')
1253  ret += toLower(filename[i]);
1254  else
1255  break;
1256  }
1257 
1258  for (i = 0; i < 3; i++)
1259  {
1260  if ((8 + i) >= filename.length())
1261  break;
1262  if (filename[8 + i] != ' ')
1263  {
1264  if (i == 0)
1265  ret += '.';
1266  ret += toLower(filename[8 + i]);
1267  }
1268  else
1269  break;
1270  }
1271 
1272  ret += '\0';
1273 
1274  return String(static_cast<const char *>(ret));
1275 }
1276 
1277 void FatFilesystem::truncate(File *pFile)
1278 {
1279  NOTICE("FatFilesystem::truncate");
1280 
1281  // First of all, set the file size to zero, so that if the file is used
1282  // elsewhere it's updated.
1283  updateFileSize(pFile, -pFile->getSize());
1284  pFile->setSize(0);
1285 
1286  // And then clean up its cluster chain so we only have one remaining
1287  // Then, clean up the cluster chain
1288  uint32_t clus = pFile->getInode(), prev = 0;
1289  if (clus != 0)
1290  {
1291  prev = clus;
1292  clus = getClusterEntry(clus, true);
1293  setClusterEntry(prev, eofValue(), true);
1294 
1295  // If the second cluster is not EOF, clean up the chain
1296  if (!isEof(clus))
1297  {
1298  while (!isEof(clus))
1299  {
1300  prev = clus;
1301  clus = getClusterEntry(clus, true);
1302  setClusterEntry(prev, 0, true);
1303  }
1304  setClusterEntry(prev, 0, true);
1305  }
1306  }
1307 }
1308 
1309 void FatFilesystem::extend(File *pFile, size_t size)
1310 {
1311  // The File object still has the old size until after we return.
1312  if (pFile->getSize() >= size)
1313  {
1314  // Don't extend - no need.
1315  return;
1316  }
1317 
1318  uint32_t firstClus = pFile->getInode();
1319  int64_t sizeChange = size - pFile->getSize();
1320 
1321  size_t clusSize = m_Superblock.BPB_SecPerClus * m_Superblock.BPB_BytsPerSec;
1322 
1323  // Find a free cluster for the file if none exists yet.
1324  if (firstClus == 0)
1325  {
1326  // Get an available free cluster.
1327  uint32_t freeClus = findFreeCluster();
1328  if (freeClus == 0)
1329  {
1330  SYSCALL_ERROR(NoSpaceLeftOnDevice);
1331  return;
1332  }
1333 
1334  // This cluster is now EOF (first cluster of the file we're linking in)
1335  setClusterEntry(freeClus, eofValue(), false);
1336  firstClus = freeClus;
1337 
1338  // Update the cluster and file object.
1339  pFile->setInode(freeClus);
1340  setCluster(pFile, freeClus);
1341 
1342  // Do we need to do anything more?
1343  if (clusSize >= size)
1344  {
1345  return;
1346  }
1347  }
1348 
1349  uint32_t finalOffset = size;
1350  uint32_t clus = 0;
1351 
1352  // Figure out how many (if any) additional clusters we need to link in now.
1353  int i = clusSize;
1354  int j = pFile->getSize() / i;
1355  if (pFile->getSize() % i)
1356  j++; // extra cluster (integer division)
1357  if (j == 0)
1358  j = 1; // always one cluster
1359 
1360  uint32_t finalCluster = j * i;
1361  uint32_t numExtraBytes = 0;
1362 
1363  // Do we need to link in extra clusters?
1364  if (finalOffset > finalCluster)
1365  {
1366  numExtraBytes = finalOffset - finalCluster;
1367 
1368  j = numExtraBytes / i;
1369  if (numExtraBytes % i)
1370  j++;
1371 
1372  clus = firstClus;
1373 
1374  uint32_t lastClus = clus;
1375  while (!isEof(clus))
1376  {
1377  lastClus = clus;
1378  clus = getClusterEntry(clus, false);
1379  }
1380 
1381  uint32_t prev = 0;
1382  for (i = 0; i < j; i++)
1383  {
1384  prev = lastClus;
1385  lastClus = findFreeCluster();
1386  if (!lastClus)
1387  {
1388  SYSCALL_ERROR(NoSpaceLeftOnDevice);
1389  return;
1390  }
1391 
1392  setClusterEntry(prev, lastClus, false);
1393  }
1394 
1395  // Final cluster must always point to EOF.
1396  setClusterEntry(lastClus, eofValue(), false);
1397  }
1398 
1399  // Update the directory now that we are done with the FAT.
1400  updateFileSize(pFile, sizeChange);
1401 }
1402 
1404  File *parentDir, const String &filename, uint32_t mask, bool bDirectory,
1405  uint32_t dirClus)
1406 {
1407  // Validate input
1408  if (!parentDir->isDirectory())
1409  {
1410  return 0;
1411  }
1412 
1413  FatFileInfo info;
1414  info.creationTime = 0;
1415  info.modifiedTime = 0;
1416  info.accessedTime = 0;
1417 
1418  // Directory or File?
1419  // Note that new files in FAT always have a zero cluster, but new
1420  // directories require a cluster (to keep the "." and ".." entries from
1421  // jumping in)
1422  File *pFile;
1423  if (bDirectory)
1424  {
1425  pFile = new FatDirectory(filename, dirClus, this, parentDir, info);
1426 
1427  char *buffer = new char[m_BlockSize];
1428  ByteSet(buffer, 0, m_BlockSize);
1429 
1430  // Clean out the clusters for the directory before creating ./..
1431  // entries.
1432  uint32_t clus = dirClus;
1433  do
1434  {
1435  // Write zero cluster.
1436  writeCluster(clus, reinterpret_cast<uintptr_t>(buffer));
1437  clus = getClusterEntry(clus);
1438  } while (!isEof(clus));
1439  }
1440  else
1441  {
1442  // Deviation from the spec here: Because the 'inode' is used for fstat,
1443  // we can't leave it at zero or else all newly created files without
1444  // data will look the same!
1445  uint32_t clus = findFreeCluster();
1446  setClusterEntry(clus, eofValue());
1447  pFile = new FatFile(
1448  filename, 0, 0, 0, clus, this, 0,
1449  0xdeadbeef, // Sentinel values that'll throw an error if they're
1450  // used
1451  0xbeefdead, // before being set to correct values.
1452  parentDir);
1453  }
1454 
1455  FatDirectory *parent =
1456  static_cast<FatDirectory *>(Directory::fromFile(parentDir));
1457  if (!parent->addEntry(filename, pFile, (bDirectory ? 1 : 0)))
1458  {
1459  delete pFile;
1460  return 0;
1461  }
1462 
1463  return pFile;
1464 }
1465 
1467  File *parent, const String &filename, uint32_t mask)
1468 {
1469  File *f = createFile(parent, filename, mask, false);
1470  return (f != 0);
1471 }
1472 
1474  File *parent, const String &filename, uint32_t mask)
1475 {
1476  // Allocate a cluster for the directory itself
1477  uint32_t clus = findFreeCluster(true);
1478  if (!clus)
1479  return false;
1480 
1481  File *f = createFile(parent, filename, mask, true, clus);
1482  if (!f)
1483  {
1484  setClusterEntry(clus, 0);
1485  return false;
1486  }
1487 
1488  FatDirectory *fatDir = static_cast<FatDirectory *>(f);
1489  setClusterEntry(clus, eofValue());
1490  fatDir->setInode(clus);
1491  setCluster(f, clus);
1492 
1493  File *dot = createFile(f, String("."), 0, true, clus);
1494  File *dotdot = createFile(f, String(".."), 0, true, parent->getInode());
1495 
1496  if (!dot || !dotdot)
1497  {
1498  // If either is valid, remove it from the directory, then remove
1499  // ourselves
1500  if (dot)
1501  remove(f, dot);
1502  if (dotdot)
1503  remove(f, dotdot);
1504  remove(parent, f);
1505  delete f;
1506  return false;
1507  }
1508 
1509  setCluster(dot, dot->getInode());
1510  setCluster(dotdot, dotdot->getInode());
1511 
1512  return true;
1513 }
1514 
1516  File *parent, const String &filename, const String &value)
1517 {
1518  // Validate input
1519  if (!parent->isDirectory())
1520  {
1521  return false;
1522  }
1523 
1524  FatFileInfo info;
1525  info.creationTime = 0;
1526  info.modifiedTime = 0;
1527  info.accessedTime = 0;
1528 
1529  // Deviation from the spec here: Because the 'inode' is used for fstat,
1530  // we can't leave it at zero or else all newly created files without
1531  // data will look the same!
1532  uint32_t clus = findFreeCluster();
1533  setClusterEntry(clus, eofValue());
1534  File *pFile = new FatSymlink(
1535  filename, 0, 0, 0, clus, this, 0,
1536  0xdeadbeef, // Sentinel values that'll throw an error if they're used
1537  0xbeefdead, // before being set to correct values.
1538  parent);
1539 
1540  String symlinkFilename = filename;
1541  symlinkFilename += FatDirectory::symlinkSuffix();
1542 
1543  FatDirectory *fatParent =
1544  static_cast<FatDirectory *>(Directory::fromFile(parent));
1545  if (!fatParent->addEntry(symlinkFilename, pFile, 0))
1546  {
1547  delete pFile;
1548  return 0;
1549  }
1550 
1551  // Write symlink target.
1552  pFile->write(
1553  0, value.length(),
1554  reinterpret_cast<uintptr_t>(static_cast<const char *>(value)));
1555 
1556  return pFile;
1557 }
1558 
1559 bool FatFilesystem::remove(File *parent, File *file)
1560 {
1561  FatDirectory *parentDir =
1562  static_cast<FatDirectory *>(Directory::fromFile(parent));
1563 
1564  // Firstly, remove from the directory itself
1565  if (!parentDir->removeEntry(file))
1566  return false;
1567 
1568  // LockGuard<Mutex> guard(m_FatLock);
1569 
1570  // Then, clean up the cluster chain
1571  uint32_t clus = file->getInode();
1572  if (clus != 0)
1573  {
1574  uint32_t prev = 0;
1575  while (true)
1576  {
1577  prev = clus;
1578  clus = getClusterEntry(clus, false);
1579  setClusterEntry(prev, 0, false);
1580 
1581  if (clus == 0)
1582  {
1583  ERROR("Found a zero cluster during FatFilesystem::remove...");
1584  break;
1585  }
1586 
1587  if (isEof(clus))
1588  break;
1589  }
1590  }
1591 
1592  return true;
1593 }
1594 
1595 static bool initFat()
1596 {
1597  VFS::instance().addProbeCallback(&FatFilesystem::probe);
1598  return true;
1599 }
1600 
1601 static void destroyFat()
1602 {
1603 }
1604 
1605 MODULE_INFO("fat", &initFat, &destroyFat, "vfs");
void writeDirectoryEntry(Dir *dir, uint32_t clus, uint32_t offset)
Disk * m_pDisk
Definition: Filesystem.h:137
void updateFileSize(File *pFile, int64_t sizeChange)
virtual bool initialise(Disk *pDisk)
virtual bool createDirectory(File *parent, const String &filename, uint32_t mask)
void setCluster(File *pFile, uint32_t clus)
virtual bool createSymlink(File *parent, const String &filename, const String &value)
virtual File * getRoot() const
uint32_t setClusterEntry(uint32_t cluster, uint32_t value, bool bLock=true)
bool readSectorBlock(uint32_t sec, size_t size, uintptr_t buffer) const
void writeDirectoryPortion(uint32_t clus, void *p)
virtual bool removeEntry(File *pFile)
Dir * getDirectoryEntry(uint32_t clus, uint32_t offset) const
static Directory * fromFile(File *pF)
Definition: Directory.h:50
bool createFile(const StringView &path, uint32_t mask, File *pStartNode=0)
Definition: Filesystem.cc:75
uint32_t findFreeCluster(bool bLock=false)
virtual void setInode(uintptr_t inode)
Definition: FatDirectory.cc:62
Definition: String.h:49
void addProbeCallback(Filesystem::ProbeCallback callback)
Definition: VFS.cc:298
static VFS & instance()
Definition: VFS.cc:56
uint32_t getClusterEntry(uint32_t cluster, bool bLock=true)
Definition: Disk.h:32
virtual bool createFile(File *parent, const String &filename, uint32_t mask)
void * readDirectoryPortion(uint32_t clus) const
bool writeCluster(uint32_t block, uintptr_t buffer)
#define WARNING(text)
Definition: Log.h:78
virtual uintptr_t read(uint64_t location)
Definition: Disk.cc:56
String convertFilenameFrom(String filename) const
bool readCluster(uint32_t block, uintptr_t buffer) const
#define NOTICE(text)
Definition: Log.h:74
virtual String getFullPath(bool bWithLabel=true)
Definition: File.cc:718
Definition: Log.h:136
static Scheduler & instance()
Definition: Scheduler.h:48
virtual void write(uint64_t location)
Definition: Disk.cc:61
virtual String getVolumeLabel() const
Definition: ext2.h:175
FatFile(const File &file)
String getName() const
Definition: File.cc:411
virtual void getName(String &str)
Definition: Disk.cc:46
void rstrip()
Definition: String.cc:501
String convertFilenameTo(String filename) const
#define ERROR(text)
Definition: Log.h:82
bool m_bReadOnly
Definition: Filesystem.h:135
virtual bool isDirectory()
Definition: File.cc:436
void yield()
Definition: Scheduler.cc:135
Definition: Log.h:138
#define FATAL(text)
Definition: Log.h:89
virtual bool addEntry(String filename, File *pFile, size_t type)
Definition: FatDirectory.cc:81
virtual bool remove(File *parent, File *file)
uint32_t getSectorNumber(uint32_t cluster) const
Definition: File.h:66
bool writeSectorBlock(uint32_t sec, size_t size, uintptr_t buffer)
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition: File.cc:183
virtual File * getRoot() const =0