static BOOL GetNextConsecutiveChain(RDWRHandle handle, CLUSTER source, unsigned long* length) { CLUSTER current = source, label; if (!GetNthCluster(handle, source, &label)) RETURN_FTEERROR(FALSE); *length = 0; while (FAT_NORMAL(label)) { if (label != current+1) { return TRUE; } (*length)++; if (!GetNthCluster(handle, current, &label)) RETURN_FTEERROR(FALSE); } (*length)++; return TRUE; }
static BOOL CreateFatReferedMap(RDWRHandle handle) { unsigned long LabelsInFat; CLUSTER current, label; LabelsInFat = GetLabelsInFat(handle); if (!LabelsInFat) return FAIL; FatReferedMap = CreateVFSBitField(handle, LabelsInFat); if (!FatReferedMap) return FAIL; for (current = 2; current < LabelsInFat; current++) { if (!GetNthCluster(handle, current, &label)) return FALSE; if (FAT_NORMAL(label)) { if (!SetVFSBitfieldBit(FatReferedMap, label)) return FALSE; } } return TRUE; }
static BOOL CleanFatLabelChain(RDWRHandle handle, CLUSTER source) { CLUSTER label; do { if (!GetNthCluster(handle, source, &label)) RETURN_FTEERROR(FALSE); if (!WriteFatLabel(handle, source, FAT_FREE_LABEL)) RETURN_FTEERROR(FALSE); source = label; } while (FAT_NORMAL(label)); return TRUE; }
static BOOL GetNextConsecutiveChain(RDWRHandle handle, CLUSTER source, unsigned long maxlength, unsigned long* length) { CLUSTER current = source, label; unsigned long retLength; if (!GetNthCluster(handle, source, &label)) RETURN_FTEERROR(FALSE); for (retLength=1; FAT_NORMAL(label) && (label == ++current) && (retLength < maxlength); retLength++) { if (!GetNthCluster(handle, current, &label)) RETURN_FTEERROR(FALSE); } *length = retLength; return TRUE; }
static BOOL CopyClusterChain(RDWRHandle handle, CLUSTER source, CLUSTER dest) { unsigned long length; do { if (!GetNextConsecutiveChain(handle, source, &length)) RETURN_FTEERROR(FALSE); if (!CopyConsecutiveClusters(handle, source, dest, length)) RETURN_FTEERROR(FALSE); dest += length; if (!GetNthCluster(handle, source+length-1, &source)) RETURN_FTEERROR(FALSE); } while (FAT_NORMAL(source)); return TRUE; }
CLUSTER random_cluster(RDWRHandle handle, unsigned long labelsinfat) { unsigned long randomnumber; unsigned random1, random2; CLUSTER label; int fatlabelsize = GetFatLabelSize(handle); if (!fatlabelsize) return FALSE; random1 = rand() * (labelsinfat % 65536L); random2 = rand() * (labelsinfat / 65536L); randomnumber = random1 * 65536L + random2; randomnumber = (randomnumber % (labelsinfat-2))+2; while (TRUE) { if (fatlabelsize == FAT32) { if (randomnumber == GetFAT32RootCluster(handle)) { randomnumber++; continue; } } if (!GetNthCluster(handle, randomnumber, &label)) return FALSE; if (FAT_NORMAL(label) || FAT_LAST(label)) { return randomnumber; } randomnumber++; if (randomnumber == labelsinfat) randomnumber = 2; } }
/************************************************************************* ** RecoverFileChains ************************************************************************** ** Goes through the FAT and converts every cluster chain to a valid file. **************************************************************************/ static BOOL RecoverFileChains(RDWRHandle handle) { unsigned long LabelsInFat, i; unsigned long filesize; CLUSTER label; LabelsInFat = GetLabelsInFat(handle); if (!LabelsInFat) return FALSE; for (i = 2; i < LabelsInFat; i++) { if (!GetNthCluster(handle, i, &label)) return FALSE; if (FAT_NORMAL(label) || (label == FAT_LAST_LABEL)) { switch (IsStartOfChain(handle, i)) { case TRUE: if (!RecoverFileChain(handle, i, &filesize)) return FALSE; if (filesize) { if (!AddToRootDir(handle, i, filesize)) return FALSE; } break; case FAIL: return FALSE; } } } return TRUE; }
BOOL WalkDirectoryTree(RDWRHandle handle, int (*func) (RDWRHandle handle, struct DirectoryPosition* position, void** structure), void** structure) { int top = 0; struct StackElement* stack; CLUSTER cluster = 0, temp; unsigned long current = 0; struct DirectoryPosition pos; struct DirectoryEntry* entry; struct StackElement element; struct PipeStruct pipe, *ppipe = &pipe; pipe.func = func; pipe.structure = structure; pipe.stop = FALSE; if (!TraverseRootDir(handle, ActionWalker, (void**)&ppipe, TRUE)) return FALSE; if (pipe.stop) return TRUE; stack = (struct StackElement*)FTEAlloc(DIR_STACK_DEPTH * sizeof(struct StackElement)); if (!stack) return FALSE; for (;;) { /* If there still are sub directories in this directory, push the cluster of that directory. */ pos.sector = 0; pos.offset = 0; if (!GetNthSubDirectoryPosition(handle, cluster, current, &pos)) { FTEFree(stack); return FALSE; } if ((pos.sector != 0) || (pos.offset != 0)) { entry = AllocateDirectoryEntry(); if (!entry) { FTEFree(stack); return FALSE; } if (top < DIR_STACK_DEPTH) { element.cluster = cluster; element.index = current; PushDirectoryEntry(stack, &top, &element); } else { FreeDirectoryEntry(entry); /* Directory level to deep!? */ FTEFree(stack); return FALSE; } if (!GetDirectory(handle, &pos, entry)) { FreeDirectoryEntry(entry); FTEFree(stack); return FALSE; } /* Descend in the directory tree and call the function for every directory entry in that directory. */ temp = GetFirstCluster(entry); /* Don't descend in any directory that is invalid. */ if (temp && FAT_NORMAL(temp) && IsLabelValid(handle, temp)) { current = 0; cluster = temp; if (!TraverseSubdir(handle, cluster, ActionWalker, (void**) &ppipe, TRUE)) { FreeDirectoryEntry(entry); FTEFree(stack); return FALSE; } if (pipe.stop) { FreeDirectoryEntry(entry); FTEFree(stack); return TRUE; } } else /* cluster not valid, leave this directory */ { if (top-1 > 0) /* Be carefull when there are no sub directories in the volume. */ { PopDirectoryEntry(stack, &top, &element); PopDirectoryEntry(stack, &top, &element); current = element.index+1; /* Then find the next sub directory. */ cluster = element.cluster; } else { FreeDirectoryEntry(entry); break; } } FreeDirectoryEntry(entry); } /* If there are no more sub directories in the current directory, pop the current directory from the stack. */ else { if (top) /* Be carefull when there are no sub directories in the volume. */ { PopDirectoryEntry(stack, &top, &element); current = element.index+1; /* Then find the next sub directory. */ cluster = element.cluster; } else { break; } } } FTEFree(stack); return TRUE; }
BOOL ScanFileChain(RDWRHandle handle, CLUSTER firstcluster, struct DirectoryPosition* pos, struct DirectoryEntry* entry, char* filename, BOOL fixit) { char* bitfield; unsigned long labelsinfat; BOOL breakoff = FALSE; CLUSTER current = firstcluster, label, breakingcluster, lengthBreakingCluster=0; unsigned long length = 0, calculatedsize, bytespercluster; static char tempbuf[255]; BOOL retVal = TRUE; /* If it is a root directory that we have to scan see wether it is a FAT32 volume and if it is get the root cluster */ if (!firstcluster) { switch (GetFatLabelSize(handle)) { case FAT12: case FAT16: return TRUE; case FAT32: current = GetFAT32RootCluster(handle); break; default: return FAIL; } } else { bytespercluster = GetSectorsPerCluster(handle) * BYTESPERSECTOR; if (!bytespercluster) return FAIL; calculatedsize = (entry->filesize / bytespercluster) + ((entry->filesize % bytespercluster) > 0); } labelsinfat = GetLabelsInFat(handle); if (!labelsinfat) return FAIL; bitfield = CreateBitField(labelsinfat); if (!bitfield) { DestroyBitfield(bitfield); return FAIL; } SetBitfieldBit(bitfield, current); /* Initialise the checks on the directory entries */ if (entry->attribute & FA_DIREC) { InitClusterEntryChecking(handle, current, filename); switch (PreProcessClusterEntryChecking(handle, current, filename, fixit)) { case FALSE: retVal = FALSE; break; case FAIL: DestroyBitfield(bitfield); DestroyClusterEntryChecking(handle, current, filename); return FAIL; } } while (TRUE) { length++; if (!GetNthCluster(handle, current, &label)) { DestroyBitfield(bitfield); if (entry->attribute & FA_DIREC) DestroyClusterEntryChecking(handle, current, filename); return FAIL; } /* Check the read cluster: */ /* the last cluster */ if (FAT_LAST(label)) { if (entry->attribute & FA_DIREC) /* Here the current cluster is valid */ { switch (CheckEntriesInCluster(handle, current, filename, fixit)) { case FALSE: retVal = FALSE; break; case FAIL: DestroyBitfield(bitfield); if (entry->attribute & FA_DIREC) DestroyClusterEntryChecking(handle, current, filename); return FAIL; } } break; } /* Check wether it is in range */ if (FAT_NORMAL(label) && !IsLabelValid(handle, label)) { if (firstcluster) { ShowFileNameViolation(handle, filename, "%s contains an invalid cluster"); } else { ShowFileNameViolation(handle, filename, "The root directory contains an invalid cluster"); } breakoff = TRUE; breakingcluster = current; retVal = FALSE; } /* bad cluster */ if (FAT_BAD(label)) { if (firstcluster) { ShowFileNameViolation(handle, filename, "%s contains a bad cluster"); } else { ShowFileNameViolation(handle, filename, "The root directory contains a bad cluster"); } breakingcluster = current; breakoff = TRUE; retVal = FALSE; } if (FAT_FREE(label)) { if (firstcluster) { ShowFileNameViolation(handle, filename, "%s contains a free cluster"); } else { ShowFileNameViolation(handle, filename, "The root directory contains a free cluster"); } breakoff = TRUE; breakingcluster = current; retVal = FALSE; } /* Check wether there is a loop */ if (!breakoff && GetBitfieldBit(bitfield, label)) { if (firstcluster) { ShowFileNameViolation(handle, filename, "%s contains a loop"); } else { ShowFileNameViolation(handle, filename, "The root directory contains a loop"); } breakoff = TRUE; breakingcluster = current; retVal = FALSE; } /* if ((firstcluster && ((entry->attribute & FA_DIREC) == 0)) && (length > calculatedsize) && (lengthBreakingCluster == 0)) { lengthBreakingCluster = current; } */ if (breakoff) { if (fixit) { if (!WriteFatLabel(handle, breakingcluster, FAT_LAST_LABEL)) { DestroyBitfield(bitfield); if (entry->attribute & FA_DIREC) DestroyClusterEntryChecking(handle, current, filename); return FAIL; } } break; } SetBitfieldBit(bitfield, label); if (entry->attribute & FA_DIREC) /* Here the current cluster is valid */ { switch (CheckEntriesInCluster(handle, current, filename, fixit)) { case FALSE: retVal = FALSE; break; case FAIL: DestroyBitfield(bitfield); if (entry->attribute & FA_DIREC) DestroyClusterEntryChecking(handle, current, filename); return FAIL; } } current = label; } /* Check the length of the file */ if (firstcluster) { /* if (((entry->attribute & FA_DIREC) == 0) && (length > calculatedsize)) { sprintf(tempbuf, "%%s has an invalid size, the size should be about %lu, but the entry says it's %lu", length * bytespercluster, entry->filesize); ShowFileNameViolation(handle, filename, tempbuf); if (fixit && !WriteFatLabel(handle, lengthBreakingCluster, FAT_LAST_LABEL)) { DestroyBitfield(bitfield); if (entry->attribute & FA_DIREC) DestroyClusterEntryChecking(handle, current, filename); return FAIL; } retVal = FALSE; } */ if (((entry->attribute & FA_DIREC) == 0) && (length != calculatedsize)) { sprintf(tempbuf, "%%s has an invalid size, the size should be about %lu, but the entry says it's %lu", length * bytespercluster, entry->filesize); ShowFileNameViolation(handle, filename, tempbuf); if (fixit) { /* Notice that we are modifying the filesize of the same entry in chkentrs.c, the entry shall be written to disk there. */ entry->filesize = length * bytespercluster; } retVal = FALSE; } } /* Destroy the checks on the directory entries */ if (entry->attribute & FA_DIREC) { switch (PostProcessClusterEntryChecking(handle, current, filename, fixit)) { case FALSE: retVal = FALSE; break; case FAIL: retVal = FAIL; } DestroyClusterEntryChecking(handle, current, filename); } DestroyBitfield(bitfield); return retVal; }