CLUSTER LocatePreviousDir(RDWRHandle handle, CLUSTER firstdircluster) { SECTOR* sectbuf; SECTOR sector; assert(firstdircluster); sectbuf = AllocateSector(handle); if (!sectbuf) RETURN_FTEERR(0xFFFFFFFFL); sector = ConvertToDataSector(handle, firstdircluster); if (!sector) { FreeSectors(sectbuf); RETURN_FTEERR(0xFFFFFFFFL); } if (!ReadDataSectors(handle, 1, sector, (void*) sectbuf)) { FreeSectors(sectbuf); RETURN_FTEERR(0xFFFFFFFFL); } if (IsPreviousDir(((struct DirectoryEntry*) sectbuf)[1])) { CLUSTER retVal = GetFirstCluster(&(((struct DirectoryEntry*) sectbuf)[1])); FreeSectors(sectbuf); return retVal; } SetFTEerror(FTE_FILESYSTEM_BAD); FreeSectors(sectbuf); RETURN_FTEERR(0xFFFFFFFFL); }
BOOL GetNthDirectorySector(RDWRHandle handle, CLUSTER cluster, unsigned long n, char* sector) { unsigned long entry; struct DirectoryPosition temp; /* Calculate which entry this corresponds to */ entry = n * ENTRIESPERSECTOR; if (!GetNthDirectoryPosition(handle, cluster, entry, &temp)) { return FALSE; } return ReadDataSectors(handle, 1, temp.sector, sector); }
/* Beware of circular references: fatpos1 = cluster2 cluster1 = clustervalue2 A -> B -> C D -> A -> B D -> A -> B -> C => D -> B -> A -> C A: C A: A / B: B A D: B cluster1 = fatpos2 clustervalue1 = cluster2 A -> B -> C B -> C -> D A -> B -> C -> D => A -> C -> B -> D C: C B A: C B: D B: B / */ BOOL SwapClusters (RDWRHandle handle, CLUSTER clust1, CLUSTER clust2) { BOOL found, IsInFAT1 = FALSE, IsInFAT2 = FALSE, error = FALSE; CLUSTER freeclust, clustervalue1, fatpos1, fatpos2; CLUSTER clustervalue2, dircluster1, dircluster2; unsigned char sectorspercluster; SECTOR startsector; struct DirectoryPosition dirpos1, dirpos2; struct DirectoryEntry entry; unsigned long neededmem; void *MemCluster; BOOL DOTSProcessed1, DOTSProcessed2; SECTOR srcsector, destsector; /* First check wether we shouldn't be using RelocateCluster instead. */ if (!ReadFatLabel (handle, clust1, &clustervalue1)) return FALSE; if (!ReadFatLabel (handle, clust2, &clustervalue2)) return FALSE; if (FAT_FREE (clustervalue1) && (FAT_FREE (clustervalue2))) { return TRUE; } if (FAT_FREE (clustervalue1)) { return RelocateCluster (handle, clust2, clust1); } if (FAT_FREE (clustervalue2)) { return RelocateCluster (handle, clust1, clust2); } /* See if we have enough memory to load the data for one cluster into memory. */ sectorspercluster = GetSectorsPerCluster (handle); if (!sectorspercluster) return FALSE; neededmem = sectorspercluster * BYTESPERSECTOR; MemCluster = malloc (neededmem); if (MemCluster) { /* First prepare the first cluster. */ /* See where the cluster is refered */ /* In FAT? */ if (!FindClusterInFAT (handle, clust1, &fatpos1)) { free (MemCluster); return FALSE; } /* No, then look if this is the first cluster of a file. */ if (!fatpos1) { if (!FindClusterInDirectories (handle, clust1, &dirpos1, &found)) { free (MemCluster); return FALSE; } if (!found) { free (MemCluster); return FALSE; /* Non valid cluster! */ } else { /* Special case: if this is the first cluster of a directory then adjust all the . and .. pointers to reflect the new position on the volume. */ if (!GetDirectory (handle, &dirpos1, &entry)) { free (MemCluster); return FALSE; } if (entry.attribute & FA_DIREC) { dircluster1 = GetFirstCluster (&entry); if (!AdaptCurrentAndPreviousDirs(handle, dircluster1, clust2)) { AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; } DOTSProcessed1 = TRUE; } } } else { IsInFAT1 = TRUE; } /* Then prepare the second cluster. */ /* See where the cluster is refered */ /* In FAT? */ if (!FindClusterInFAT (handle, clust2, &fatpos2)) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; } /* No, then look if this is the first cluster of a file. */ if (!fatpos2) { if (!FindClusterInDirectories (handle, clust2, &dirpos2, &found)) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; } if (!found) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; /* Non valid cluster! */ } else { /* Special case: if this is the first cluster of a directory then adjust all the . and .. pointers to reflect the new position on the volume. */ if (!GetDirectory (handle, &dirpos2, &entry)) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; } if (entry.attribute & FA_DIREC) { dircluster2 = GetFirstCluster (&entry); if (!AdaptCurrentAndPreviousDirs(handle, dircluster2, clust1)) { AdaptCurrentAndPreviousDirs (handle, dircluster2, clust2); AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); free (MemCluster); return FALSE; } DOTSProcessed2 = TRUE; } } } else { IsInFAT2 = TRUE; } startsector = ConvertToDataSector (handle, clust1); if (!startsector) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); if (DOTSProcessed2) AdaptCurrentAndPreviousDirs (handle, dircluster2, clust2); free (MemCluster); return FALSE; } /* Then copy the data of the second cluster to the new position */ /* Copy all sectors in this cluster to the new position */ srcsector = ConvertToDataSector (handle, clust2); if (!srcsector) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); if (DOTSProcessed2) AdaptCurrentAndPreviousDirs (handle, dircluster2, clust2); free (MemCluster); return FALSE; } destsector = ConvertToDataSector (handle, clust1); if (!startsector) { if (DOTSProcessed1) AdaptCurrentAndPreviousDirs (handle, dircluster1, clust1); if (DOTSProcessed2) AdaptCurrentAndPreviousDirs (handle, dircluster2, clust2); free (MemCluster); return FALSE; } /* AS OF THIS POINT WE WILL NOT BE ABLE TO BACKTRACK, THEREFORE WE KEEP ON GOING EVEN IF THERE WERE ERRORS. */ /* Change the pointers of the first cluster that has to be moved to the second cluster. */ /* Write the entry in the FAT */ if (clust2 == clustervalue1) /* Beware of circular references */ { if (!WriteFatLabel (handle, clust2, clust1)) error = TRUE; } else { if (!WriteFatLabel (handle, clust2, clustervalue1)) error = TRUE; } /* Adjust the pointer to the relocated cluster */ if (IsInFAT1) /* the previous one in the file */ { if (fatpos1 != clust2) /* Beware of circular references */ { if (!WriteFatLabel (handle, fatpos1, clust2)) error = TRUE; } } else /* or the directory entry to the file */ { if (!GetDirectory (handle, &dirpos1, &entry)) error = TRUE; if (GetFirstCluster (&entry) != clust2) { SetFirstCluster (clust2, &entry); if (!WriteDirectory (handle, &dirpos1, &entry)) error = TRUE; } } /* Change the pointers of the second cluster that has to be moved to the first cluster. */ /* Write the entry in the FAT */ if (clust1 == clustervalue2) /* Beware of circular references */ { if (!WriteFatLabel (handle, clust1, clustervalue1)) error = TRUE; } else { if (!WriteFatLabel (handle, clust1, clustervalue2)) error = TRUE; } /* Adjust the pointer to the relocated cluster */ if (IsInFAT2) /* the previous one in the file */ { if (fatpos2 != clust1) /* Beware of circular references */ { if (!WriteFatLabel (handle, fatpos2, clust1)) error = TRUE; } } else /* or the directory entry to the file */ { if (!GetDirectory (handle, &dirpos2, &entry)) error = TRUE; if (GetFirstCluster (&entry) != clust1) /* Beware of circular references */ { SetFirstCluster (clust1, &entry); if (!WriteDirectory (handle, &dirpos2, &entry)) error = TRUE; }