static NTSTATUS VfatMarkVolumeDirty(PVFAT_IRP_CONTEXT IrpContext) { ULONG eocMark; PDEVICE_EXTENSION DeviceExt; NTSTATUS Status = STATUS_SUCCESS; DPRINT("VfatMarkVolumeDirty(IrpContext %p)\n", IrpContext); DeviceExt = IrpContext->DeviceExt; if (!(DeviceExt->VolumeFcb->Flags & VCB_IS_DIRTY)) { Status = GetNextCluster(DeviceExt, 1, &eocMark); if (NT_SUCCESS(Status)) { /* unset clean shutdown bit */ eocMark &= ~DeviceExt->CleanShutBitMask; Status = WriteCluster(DeviceExt, 1, eocMark); } } DeviceExt->VolumeFcb->Flags &= ~VCB_CLEAR_DIRTY; return Status; }
//Release one cluster chain,the cluster chain starts from dwStartCluster. BOOL ReleaseClusterChain(__FAT32_FS* pFat32Fs,DWORD dwStartCluster) { DWORD dwNextCluster = 0; DWORD dwCurrCluster = 0; BOOL bResult = FALSE; if((NULL == pFat32Fs) || (dwStartCluster < 2) || IS_EOC(dwStartCluster)) { goto __TERMINAL; } dwNextCluster = dwStartCluster; while(!IS_EOC(dwNextCluster)) { dwCurrCluster = dwNextCluster; if(!GetNextCluster(pFat32Fs,&dwNextCluster)) { goto __TERMINAL; } ReleaseCluster(pFat32Fs,dwCurrCluster); //Release current one. } bResult = TRUE; __TERMINAL: return bResult; }
BOOL GetCluster(PVOLINFO pVolInfo, PFINDINFO pFindInfo, USHORT usClusterIndex) { USHORT usIndex; if (usClusterIndex >= pFindInfo->usTotalClusters) return FALSE; if (!pFindInfo->pInfo->rgClusters[usClusterIndex]) { for (usIndex = pFindInfo->usClusterIndex; usIndex < usClusterIndex; usIndex++) { pFindInfo->pInfo->rgClusters[usIndex + 1] = GetNextCluster( pVolInfo, pFindInfo->pInfo->rgClusters[usIndex]); if (!pFindInfo->pInfo->rgClusters[usIndex + 1]) pFindInfo->pInfo->rgClusters[usIndex + 1] = FAT_EOF; if (pFindInfo->pInfo->rgClusters[usIndex + 1] == FAT_EOF) return FALSE; } } if (pFindInfo->pInfo->rgClusters[usClusterIndex] == FAT_EOF) return FALSE; if (ReadCluster( pVolInfo, pFindInfo->pInfo->rgClusters[usClusterIndex], pFindInfo->pInfo->pDirEntries, 0)) return FALSE; pFindInfo->usClusterIndex = usClusterIndex; return TRUE; }
void Clust::DeleteMetric(unsigned uIndex) { for (unsigned uNodeIndex = GetFirstCluster(); uNodeIndex != uInsane; uNodeIndex = GetNextCluster(uNodeIndex)) { if (uIndex == uNodeIndex) continue; DeleteMetric(uIndex, uNodeIndex); } }
NTSTATUS OffsetToCluster( PDEVICE_EXTENSION DeviceExt, ULONG FirstCluster, ULONG FileOffset, PULONG Cluster, BOOLEAN Extend) { ULONG CurrentCluster; ULONG i; NTSTATUS Status; /* DPRINT("OffsetToCluster(DeviceExt %x, Fcb %x, FirstCluster %x," " FileOffset %x, Cluster %x, Extend %d)\n", DeviceExt, Fcb, FirstCluster, FileOffset, Cluster, Extend); */ if (FirstCluster == 0) { DbgPrint("OffsetToCluster is called with FirstCluster = 0!\n"); ASSERT(FALSE); } if (FirstCluster == 1) { /* root of FAT16 or FAT12 */ *Cluster = DeviceExt->FatInfo.rootStart + FileOffset / (DeviceExt->FatInfo.BytesPerCluster) * DeviceExt->FatInfo.SectorsPerCluster; return STATUS_SUCCESS; } else { CurrentCluster = FirstCluster; if (Extend) { for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) { Status = GetNextClusterExtend (DeviceExt, CurrentCluster, &CurrentCluster); if (!NT_SUCCESS(Status)) return Status; } *Cluster = CurrentCluster; } else { for (i = 0; i < FileOffset / DeviceExt->FatInfo.BytesPerCluster; i++) { Status = GetNextCluster (DeviceExt, CurrentCluster, &CurrentCluster); if (!NT_SUCCESS(Status)) return Status; } *Cluster = CurrentCluster; } return STATUS_SUCCESS; } }
/* * Return the next cluster in a FAT chain, possibly extending the chain if * necessary */ NTSTATUS NextCluster( PDEVICE_EXTENSION DeviceExt, ULONG FirstCluster, PULONG CurrentCluster, BOOLEAN Extend) { if (FirstCluster == 1) { (*CurrentCluster) += DeviceExt->FatInfo.SectorsPerCluster; return STATUS_SUCCESS; } else { if (Extend) return GetNextClusterExtend(DeviceExt, (*CurrentCluster), CurrentCluster); else return GetNextCluster(DeviceExt, (*CurrentCluster), CurrentCluster); } }
VOID CheckSpace(PDRIVEINFO pDrive) { ULONG ulCluster; printf("\nChecking for lost clusters\n"); ulTotalFree = 0; for (ulCluster = 2; ulCluster < pDrive->ulTotalClusters + 2; ulCluster++) { ULONG ulNext = GetNextCluster(pDrive, ulCluster); if (!(ulNext & FAT_EOF)) { MarkCluster(pDrive, ulCluster); ulTotalFree++; } else { if (!ClusterInUse(pDrive, ulCluster)) printf("Cluster %lu is lost (%8.8lX)\n", ulCluster, ulNext); } } }
ULONG NextSector(ULONG Sector) { Sector += 1; // // This may look confusing, but it saves us 16 bytes over a % operation. // if( Sector % ( 1 << pBPB->SectorsPerCluster) == 0 ) // Just checking to see if we've used all the sectors in the current cluster. // if( (Sector & ((1 << pBPB->SectorsPerCluster)-1)) == 0 ) { ULONG Cluster = LBA2Cluster( Sector - 1 ); ULONG NewCluster = GetNextCluster( Cluster ); if( IsDataCluster( NewCluster ) && Cluster != NewCluster ) { return Cluster2LBA( NewCluster ); } Sector = 0; } return Sector; }
USHORT usReadEAS(PVOLINFO pVolInfo, ULONG ulDirCluster, PSZ pszFileName, PFEALIST * ppFEAL, BOOL fCreate) { PFEALIST pFEAL; ULONG ulCluster; PBYTE pszEAName; PBYTE pRead; USHORT rc; USHORT usClustersUsed; *ppFEAL = NULL; rc = GetEASName(pVolInfo, ulDirCluster, pszFileName, &pszEAName); if (rc) return rc; ulCluster = FindPathCluster(pVolInfo, ulDirCluster, pszEAName, NULL, NULL); free(pszEAName); if ((ulCluster && ulCluster != FAT_EOF) || fCreate) { pFEAL = gdtAlloc(MAX_EA_SIZE, FALSE); if (!pFEAL) return ERROR_NOT_ENOUGH_MEMORY; memset(pFEAL, 0, (size_t) MAX_EA_SIZE); pFEAL->cbList = sizeof (ULONG); } else pFEAL = NULL; if (!ulCluster || ulCluster == FAT_EOF) { *ppFEAL = pFEAL; return 0; } pRead = (PBYTE)pFEAL; if (f32Parms.fMessageActive & LOG_EAS) Message("usReadEAS: Reading (1) cluster %lu", ulCluster); rc = ReadCluster(pVolInfo, ulCluster, pRead, 0); if (rc) { freeseg(pFEAL); return rc; } if (pFEAL->cbList > MAX_EA_SIZE) { freeseg(pFEAL); return ERROR_EAS_DIDNT_FIT; } usClustersUsed = (USHORT)(pFEAL->cbList / pVolInfo->usClusterSize); if (pFEAL->cbList % pVolInfo->usClusterSize) usClustersUsed++; /* vreemd: zonder deze Messages lijkt deze routine mis te gaan. Optimalisatie? */ if (f32Parms.fMessageActive & LOG_EAS) Message("usReadEAS: %u clusters used", usClustersUsed); usClustersUsed--; pRead += pVolInfo->usClusterSize; while (usClustersUsed) { ulCluster = GetNextCluster(pVolInfo, ulCluster); if (!ulCluster) ulCluster = FAT_EOF; if (ulCluster == FAT_EOF) { freeseg(pFEAL); return ERROR_EA_FILE_CORRUPT; } /* vreemd: zonder deze Messages lijkt deze routine mis te gaan. Optimalisatie? */ if (f32Parms.fMessageActive & LOG_EAS) Message("usReadEAS: Reading (2) cluster %lu", ulCluster); rc = ReadCluster(pVolInfo, ulCluster, pRead, 0); if (rc) { freeseg(pFEAL); return rc; } usClustersUsed--; pRead += pVolInfo->usClusterSize; } *ppFEAL = pFEAL; return 0; }
//Append one free cluster to the tail of a cluster chain. //The pdwCurrCluster contains the laster cluster of a cluster chain,if this routine //executes successfully,it will return TRUE and pdwCurrCluster contains the cluster //number value appended to chain right now.Else FALSE will be returned and the pdwCurrCluster //keep unchanged. BOOL AppendClusterToChain(__FAT32_FS* pFat32Fs,DWORD* pdwCurrCluster) { DWORD dwCurrCluster = 0; DWORD dwNextCluster = 0; DWORD dwSector = 0; DWORD dwOffset = 0; BOOL bResult = FALSE; BYTE* pBuffer = NULL; DWORD dwEndCluster = 0; if((NULL == pFat32Fs) || (NULL == pdwCurrCluster)) { goto __TERMINAL; } dwCurrCluster = *pdwCurrCluster; if((2 > dwCurrCluster) || IS_EOC(dwCurrCluster)) { goto __TERMINAL; } dwSector = dwCurrCluster / 128; if(dwSector > pFat32Fs->dwFatSectorNum) //Exceed the FAT size. { goto __TERMINAL; } dwSector += pFat32Fs->dwFatBeginSector; //Now dwSector is the physical sector number of dwCurrCluster in fat. dwOffset = (dwCurrCluster - (dwCurrCluster / 128) * 128) * sizeof(DWORD); //Get sector offset. pBuffer = (BYTE*)LocalAlloc(LPTR,pFat32Fs->dwBytePerSector); if(NULL == pBuffer) { goto __TERMINAL; } //Try to get a free cluster. if(!GetFreeCluster(pFat32Fs,0,&dwNextCluster)) { goto __TERMINAL; } //The following operation must behind GetFreeCluster routine above,because //GetFreeCluster routine will modify the content of FAT,and this change must //be taken before the following read. //One complicated problem has been caused by this reason. if(!ReadDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+ dwSector,1,pBuffer)) { goto __TERMINAL; } //Save the next cluster to chain. *(DWORD*)(pBuffer + dwOffset) &= 0xF0000000; //Keep the leading 4 bits. *(DWORD*)(pBuffer + dwOffset) += (dwNextCluster & 0x0FFFFFFF); if(!WriteDeviceSector(pFat32Fs->pPartition, pFat32Fs->dwPartitionSatrt+ dwSector,1,pBuffer)) { ReleaseCluster(pFat32Fs,dwNextCluster); //Release this cluster. goto __TERMINAL; } dwEndCluster = *(DWORD*)(pBuffer + dwOffset); if(!GetNextCluster(pFat32Fs,&dwEndCluster)) { } bResult = TRUE; //Anything is in place. __TERMINAL: if(pBuffer) //Should release it. { LocalFree(pBuffer); } if(bResult) { *pdwCurrCluster = (dwNextCluster & 0x0FFFFFFF); } return bResult; }
//Implementation of SetFilePointer. static DWORD FatDeviceSeek(__COMMON_OBJECT* lpDrv, __COMMON_OBJECT* lpDev,__DRCB* lpDrcb) { __FAT32_FILE* pFatFile = NULL; DWORD dwSeekRet = -1; if((NULL == lpDrv) || (NULL == lpDev) || (NULL == lpDrcb)) { return dwSeekRet; } pFatFile = (__FAT32_FILE*)(((__DEVICE_OBJECT*)lpDev)->lpDevExtension); if( NULL != pFatFile) { __FAT32_FS* pFatFs = pFatFile->pFileSystem; DWORD dwWhereBegin = (DWORD)lpDrcb->lpInputBuffer;//((DWORD*)lpDrcb->lpInputBuffer); DWORD dwOffsetPos = *((INT*)lpDrcb->dwExtraParam1); DWORD dwClusterNum = 0; DWORD i = 0; //_hx_printf("FatDeviceSeek: where=%d,pos=%d\r\n",dwWhereBegin,dwOffsetPos); switch(dwWhereBegin) { case FILE_FROM_BEGIN: { pFatFile->dwCurrPos = dwOffsetPos; } break; case FILE_FROM_CURRENT: { pFatFile->dwCurrPos += dwOffsetPos; } break; case FILE_FROM_END: { pFatFile->dwCurrPos = pFatFile->dwFileSize; } break; default: { return dwSeekRet; } } if(pFatFile->dwCurrPos > pFatFile->dwFileSize) { pFatFile->dwCurrPos = pFatFile->dwFileSize; } if(pFatFile->dwCurrPos < pFatFs->dwClusterSize ) { dwClusterNum = 1; } else { dwClusterNum = pFatFile->dwCurrPos/pFatFs->dwClusterSize; if((pFatFile->dwCurrPos+1)%pFatFs->dwClusterSize) { dwClusterNum ++; } } pFatFile->dwCurrClusNum = pFatFile->dwStartClusNum; for(i=0; i< (dwClusterNum-1); i++) { DWORD dwNextNum = pFatFile->dwCurrClusNum; if(!GetNextCluster(pFatFs,&dwNextNum)) { return dwSeekRet; } pFatFile->dwCurrClusNum = dwNextNum; } pFatFile->dwClusOffset = pFatFile->dwCurrPos % pFatFs->dwClusterSize; dwSeekRet = pFatFile->dwCurrPos; } return dwSeekRet; }
int far pascal __loadds FS_FINDFIRST(struct cdfsi far * pcdfsi, /* pcdfsi */ struct cdfsd far * pcdfsd, /* pcdfsd */ char far * pName, /* pName */ unsigned short usCurDirEnd, /* iCurDirEnd */ unsigned short usAttr, /* attr */ struct fsfsi far * pfsfsi, /* pfsfsi */ struct fsfsd far * pfsfsd, /* pfsfsd */ char far * pData, /* pData */ unsigned short cbData, /* cbData */ unsigned short far * pcMatch, /* pcMatch */ unsigned short usLevel, /* level */ unsigned short usFlags) /* flags */ { PVOLINFO pVolInfo; PFINDINFO pFindInfo = (PFINDINFO)pfsfsd; USHORT rc; USHORT usIndex; USHORT usNeededLen; USHORT usNumClusters; ULONG ulCluster; ULONG ulDirCluster; PSZ pSearch; PFINFO pNext; ULONG ulNeededSpace; USHORT usEntriesWanted; EAOP EAOP; PROCINFO ProcInfo; if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDFIRST for %s attr %X, Level %d, cbData %u, MaxEntries %u", pName, usAttr, usLevel, cbData, *pcMatch); usEntriesWanted = *pcMatch; *pcMatch = 0; if (strlen(pName) > FAT32MAXPATH) { rc = ERROR_FILENAME_EXCED_RANGE; goto FS_FINDFIRSTEXIT; } memset(pfsfsd, 0, sizeof (struct fsfsd)); pVolInfo = GetVolInfo(pfsfsi->fsi_hVPB); if (IsDriveLocked(pVolInfo)) { rc = ERROR_DRIVE_LOCKED; goto FS_FINDFIRSTEXIT; } switch (usLevel) { case FIL_STANDARD : usNeededLen = sizeof (FILEFNDBUF) - CCHMAXPATHCOMP; break; case FIL_QUERYEASIZE : usNeededLen = sizeof (FILEFNDBUF2) - CCHMAXPATHCOMP; break; case FIL_QUERYEASFROMLIST : usNeededLen = sizeof (EAOP) + sizeof (FILEFNDBUF3) + sizeof (ULONG); break; default : rc = ERROR_NOT_SUPPORTED; goto FS_FINDFIRSTEXIT; } if (usFlags == FF_GETPOS) usNeededLen += sizeof (ULONG); if (cbData < usNeededLen) { rc = ERROR_BUFFER_OVERFLOW; goto FS_FINDFIRSTEXIT; } rc = MY_PROBEBUF(PB_OPWRITE, pData, cbData); if (rc) { Message("FAT32: Protection VIOLATION in FS_FINDFIRST! (SYS%d)", rc); return rc; } if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(&EAOP, pData, sizeof (EAOP)); rc = MY_PROBEBUF(PB_OPREAD, (PBYTE)EAOP.fpGEAList, (USHORT)EAOP.fpGEAList->cbList); if (rc) goto FS_FINDFIRSTEXIT; } memset(pData, 0, cbData); usNumClusters = 0; ulDirCluster = FindDirCluster(pVolInfo, pcdfsi, pcdfsd, pName, usCurDirEnd, RETURN_PARENT_DIR, &pSearch); if (ulDirCluster == FAT_EOF) { rc = ERROR_PATH_NOT_FOUND; goto FS_FINDFIRSTEXIT; } ulCluster = ulDirCluster; while (ulCluster && ulCluster != FAT_EOF) { usNumClusters++; ulCluster = GetNextCluster( pVolInfo, ulCluster); } ulNeededSpace = sizeof (FINFO) + (usNumClusters - 1) * sizeof (ULONG); ulNeededSpace += pVolInfo->usClusterSize; GetProcInfo(&ProcInfo, sizeof ProcInfo); pFindInfo->pInfo = (PFINFO)malloc((size_t)ulNeededSpace); if (!pFindInfo->pInfo) { rc = ERROR_NOT_ENOUGH_MEMORY; goto FS_FINDFIRSTEXIT; } memset(pFindInfo->pInfo, 0, (size_t)ulNeededSpace); if (!pVolInfo->pFindInfo) pVolInfo->pFindInfo = pFindInfo->pInfo; else { pNext = (PFINFO)pVolInfo->pFindInfo; while (pNext->pNextEntry) pNext = (PFINFO)pNext->pNextEntry; pNext->pNextEntry = pFindInfo->pInfo; } memcpy(&pFindInfo->pInfo->EAOP, &EAOP, sizeof (EAOP)); pFindInfo->usEntriesPerCluster = pVolInfo->usClusterSize / sizeof (DIRENTRY); pFindInfo->usClusterIndex = 0; pFindInfo->pInfo->rgClusters[0] = ulDirCluster; pFindInfo->usTotalClusters = usNumClusters; pFindInfo->pInfo->pDirEntries = (PDIRENTRY)(&pFindInfo->pInfo->rgClusters[usNumClusters]); if (f32Parms.fMessageActive & LOG_FIND) Message("pInfo at %lX, pDirEntries at %lX", pFindInfo->pInfo, pFindInfo->pInfo->pDirEntries); pFindInfo->pInfo->pNextEntry = NULL; memcpy(&pFindInfo->pInfo->ProcInfo, &ProcInfo, sizeof (PROCINFO)); strcpy(pFindInfo->pInfo->szSearch, pSearch); FSH_UPPERCASE(pFindInfo->pInfo->szSearch, sizeof pFindInfo->pInfo->szSearch, pFindInfo->pInfo->szSearch); pFindInfo->ulMaxEntry = ((ULONG)pVolInfo->usClusterSize / sizeof (DIRENTRY)) * usNumClusters; if (!GetCluster(pVolInfo, pFindInfo, 0)) { rc = ERROR_SYS_INTERNAL; goto FS_FINDFIRSTEXIT; } pFindInfo->ulCurEntry = 0; if (usAttr & 0x0040) { pFindInfo->fLongNames = TRUE; usAttr &= ~0x0040; } else pFindInfo->fLongNames = FALSE; pFindInfo->bMustAttr = (BYTE)(usAttr >> 8); usAttr |= (FILE_READONLY | FILE_ARCHIVED); usAttr &= (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED); pFindInfo->bAttr = (BYTE)~usAttr; if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(pData, &pFindInfo->pInfo->EAOP, sizeof (EAOP)); pData += sizeof (EAOP); cbData -= sizeof (EAOP); } rc = 0; for (usIndex = 0; usIndex < usEntriesWanted; usIndex++) { PULONG pulOrdinal; if (usFlags == FF_GETPOS) { if (cbData < sizeof (ULONG)) { rc = ERROR_BUFFER_OVERFLOW; break; } pulOrdinal = (PULONG)pData; pData += sizeof (ULONG); cbData -= sizeof (ULONG); } rc = FillDirEntry(pVolInfo, &pData, &cbData, pFindInfo, usLevel); if (!rc || (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0)) { if (usFlags == FF_GETPOS) *pulOrdinal = pFindInfo->ulCurEntry - 1; } if (rc) break; } if ((rc == ERROR_NO_MORE_FILES || rc == ERROR_BUFFER_OVERFLOW || rc == ERROR_EAS_DIDNT_FIT) && usIndex > 0) rc = 0; if (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0) usIndex = 1; *pcMatch = usIndex; FS_FINDFIRSTEXIT: if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDFIRST returned %d (%d entries)", rc, *pcMatch); if (rc && rc != ERROR_EAS_DIDNT_FIT) { FS_FINDCLOSE(pfsfsi, pfsfsd); } return rc; }
//Helper routine used to build the directory cluster list given a name. //The appropriate find handle is returned if all successfully. static __FAT32_FIND_HANDLE* BuildFindHandle(__FAT32_FS* pFat32Fs,CHAR* pszDirName) { __FAT32_FIND_HANDLE* pFindHandle = NULL; __FAT32_DIR_CLUSTER* pDirCluster = NULL; __FAT32_SHORTENTRY ShortEntry = {0}; //Short entry of target dir. DWORD dwCurrClus = 0; DWORD dwSector = 0; BOOL bResult = FALSE; if(!GetDirEntry(pFat32Fs,&pszDirName[0],&ShortEntry,NULL,NULL)) { goto __TERMINAL; } if(!(ShortEntry.FileAttributes & FILE_ATTR_DIRECTORY)) //Not a directory. { goto __TERMINAL; } pFindHandle = (__FAT32_FIND_HANDLE*)CREATE_OBJECT(__FAT32_FIND_HANDLE); if(NULL == pFindHandle) { goto __TERMINAL; } //Initialize the find hanlde object. pFindHandle->dwClusterOffset = 0; pFindHandle->dwClusterSize = pFat32Fs->dwClusterSize; pFindHandle->pClusterRoot = NULL; pFindHandle->pCurrCluster = NULL; dwCurrClus = ((DWORD)ShortEntry.wFirstClusHi << 16) + (DWORD)ShortEntry.wFirstClusLow; while(!IS_EOC(dwCurrClus)) { pDirCluster = (__FAT32_DIR_CLUSTER*)CREATE_OBJECT(__FAT32_DIR_CLUSTER); if(NULL == pDirCluster) //Can not allocate memory. { goto __TERMINAL; } pDirCluster->pCluster = (BYTE*)FatMem_Alloc(pFat32Fs->dwClusterSize); if(NULL == pDirCluster->pCluster) { goto __TERMINAL; } pDirCluster->pNext = NULL; //Now try to read the directory cluster data. dwSector = GetClusterSector(pFat32Fs,dwCurrClus); if(0 == dwSector) { goto __TERMINAL; } if(!ReadDeviceSector((__COMMON_OBJECT*)pFat32Fs->pPartition, dwSector, pFat32Fs->SectorPerClus, pDirCluster->pCluster)) //Can not read directory cluster. { goto __TERMINAL; } //Attach this cluster into directory cluster list. if(NULL == pFindHandle->pClusterRoot) //First cluster now. { pFindHandle->pClusterRoot = pDirCluster; pFindHandle->pCurrCluster = pDirCluster; } else //Not the first cluster,pCurrCluster pointing to the last node. { pFindHandle->pCurrCluster->pNext = pDirCluster; pFindHandle->pCurrCluster = pDirCluster; } if(!GetNextCluster(pFat32Fs,&dwCurrClus)) { goto __TERMINAL; } } pFindHandle->pCurrCluster = pFindHandle->pClusterRoot; pDirCluster = NULL; //Indicate the successful execution of above while block. bResult = TRUE; //Mark the successful flag. __TERMINAL: if(bResult) //Successful. { return pFindHandle; } else //Failed,should release the allocated resource. { if(pDirCluster) //Directory cluster object has been allocated. { if(pDirCluster->pCluster) { FatMem_Free(pDirCluster->pCluster); } FatMem_Free(pDirCluster); } //Release the directory cluster object in list. if(NULL == pFindHandle) { goto __RETURN; } while(pFindHandle->pClusterRoot) { pFindHandle->pCurrCluster = pFindHandle->pClusterRoot; pFindHandle->pClusterRoot = pFindHandle->pClusterRoot->pNext; if(pFindHandle->pCurrCluster->pCluster) { FatMem_Free(pFindHandle->pCurrCluster->pCluster); } FatMem_Free(pFindHandle->pCurrCluster); } //Release the find handle object. FatMem_Free(pFindHandle); __RETURN: return NULL; } }
//Helper routine to obtain volume lable. static BOOL GetVolumeLbl(__FAT32_FS* pFat32Fs,CHAR* pVolumeLbl) { BOOL bResult = FALSE; __FAT32_SHORTENTRY* pfse = NULL; BYTE* pBuffer = NULL; DWORD dwCurrClus = 0; DWORD dwSector = 0; CHAR Buffer[128] = {0}; INT i,j; if((NULL == pFat32Fs) || (NULL == pVolumeLbl)) { goto __TERMINAL; } //Create local buffer to contain one cluster. pBuffer = (BYTE*)FatMem_Alloc(pFat32Fs->SectorPerClus * pFat32Fs->dwBytePerSector); if(NULL == pBuffer) { PrintLine("Can not allocate memory from heap."); goto __TERMINAL; } dwCurrClus = pFat32Fs->dwRootDirClusStart; while(!IS_EOC(dwCurrClus)) //Main loop to check the root directory. { dwSector = GetClusterSector(pFat32Fs,dwCurrClus); if(0 == dwSector) //Fatal error. { goto __TERMINAL; } if(!ReadDeviceSector((__COMMON_OBJECT*)pFat32Fs->pPartition, dwSector, pFat32Fs->SectorPerClus, pBuffer)) //Can not read the appropriate sector(s). { _hx_sprintf(Buffer," Read sector failed in GetVolumeLbl,Info: %d %d %d %d %d %d %d ", dwCurrClus, dwSector, pFat32Fs->dwClusterSize, pFat32Fs->dwDataSectorStart, pFat32Fs->dwFatSectorNum, pFat32Fs->dwFatBeginSector, pFat32Fs->SectorPerClus); PrintLine(Buffer); //Only used for debugging. goto __TERMINAL; } //Now check the root directory to seek the volume ID entry. pfse = (__FAT32_SHORTENTRY*)pBuffer; for(i = 0; i < pFat32Fs->SectorPerClus * 16; i ++) { if(0xE5 == (BYTE)pfse->FileName[0]) //Empty entry. { pfse += 1; //Seek to the next entry. continue; } if(0 == pfse->FileName[0]) //All rest part is zero,no need to check futher. { break; } if(FILE_ATTR_LONGNAME == pfse->FileAttributes) //Long file name entry. { pfse += 1; continue; } if(FILE_ATTR_VOLUMEID & pfse->FileAttributes) //Volume label entry. { for(j = 0; j < 11; j ++) { pVolumeLbl[j] = pfse->FileName[j]; } pVolumeLbl[j] = 0; //Set the terminator. bResult = TRUE; goto __TERMINAL; } pfse += 1; } if(!GetNextCluster(pFat32Fs,&dwCurrClus)) { _hx_printf(Buffer,"Current cluster number is %d\n",dwCurrClus); break; } } __TERMINAL: FatMem_Free(pBuffer); return bResult; }
static NTSTATUS VfatMount (PVFAT_IRP_CONTEXT IrpContext) /* * FUNCTION: Mount the filesystem */ { PDEVICE_OBJECT DeviceObject = NULL; PDEVICE_EXTENSION DeviceExt = NULL; BOOLEAN RecognizedFS; NTSTATUS Status; PVFATFCB Fcb = NULL; PVFATFCB VolumeFcb = NULL; PVFATCCB Ccb = NULL; PDEVICE_OBJECT DeviceToMount; PVPB Vpb; UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\$$Fat$$"); UNICODE_STRING VolumeNameU = RTL_CONSTANT_STRING(L"\\$$Volume$$"); ULONG HashTableSize; ULONG eocMark; FATINFO FatInfo; DPRINT("VfatMount(IrpContext %p)\n", IrpContext); ASSERT(IrpContext); if (IrpContext->DeviceObject != VfatGlobalData->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } DeviceToMount = IrpContext->Stack->Parameters.MountVolume.DeviceObject; Vpb = IrpContext->Stack->Parameters.MountVolume.Vpb; Status = VfatHasFileSystem (DeviceToMount, &RecognizedFS, &FatInfo); if (!NT_SUCCESS(Status)) { goto ByeBye; } if (RecognizedFS == FALSE) { DPRINT("VFAT: Unrecognized Volume\n"); Status = STATUS_UNRECOGNIZED_VOLUME; goto ByeBye; } /* Use prime numbers for the table size */ if (FatInfo.FatType == FAT12) { HashTableSize = 4099; // 4096 = 4 * 1024 } else if (FatInfo.FatType == FAT16 || FatInfo.FatType == FATX16) { HashTableSize = 16411; // 16384 = 16 * 1024 } else { HashTableSize = 65537; // 65536 = 64 * 1024; } HashTableSize = FCB_HASH_TABLE_SIZE; DPRINT("VFAT: Recognized volume\n"); Status = IoCreateDevice(VfatGlobalData->DriverObject, ROUND_UP(sizeof (DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize, NULL, FILE_DEVICE_DISK_FILE_SYSTEM, DeviceToMount->Characteristics, FALSE, &DeviceObject); if (!NT_SUCCESS(Status)) { goto ByeBye; } DeviceObject->Flags = DeviceObject->Flags | DO_DIRECT_IO; DeviceExt = (PVOID) DeviceObject->DeviceExtension; RtlZeroMemory(DeviceExt, ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG)) + sizeof(HASHENTRY*) * HashTableSize); DeviceExt->FcbHashTable = (HASHENTRY**)((ULONG_PTR)DeviceExt + ROUND_UP(sizeof(DEVICE_EXTENSION), sizeof(ULONG))); DeviceExt->HashTableSize = HashTableSize; /* use same vpb as device disk */ DeviceObject->Vpb = Vpb; DeviceToMount->Vpb = Vpb; Status = VfatMountDevice(DeviceExt, DeviceToMount); if (!NT_SUCCESS(Status)) { /* FIXME: delete device object */ goto ByeBye; } DPRINT("BytesPerSector: %d\n", DeviceExt->FatInfo.BytesPerSector); DPRINT("SectorsPerCluster: %d\n", DeviceExt->FatInfo.SectorsPerCluster); DPRINT("FATCount: %d\n", DeviceExt->FatInfo.FATCount); DPRINT("FATSectors: %d\n", DeviceExt->FatInfo.FATSectors); DPRINT("RootStart: %d\n", DeviceExt->FatInfo.rootStart); DPRINT("DataStart: %d\n", DeviceExt->FatInfo.dataStart); if (DeviceExt->FatInfo.FatType == FAT32) { DPRINT("RootCluster: %d\n", DeviceExt->FatInfo.RootCluster); } switch (DeviceExt->FatInfo.FatType) { case FAT12: DeviceExt->GetNextCluster = FAT12GetNextCluster; DeviceExt->FindAndMarkAvailableCluster = FAT12FindAndMarkAvailableCluster; DeviceExt->WriteCluster = FAT12WriteCluster; DeviceExt->CleanShutBitMask = 0; break; case FAT16: case FATX16: DeviceExt->GetNextCluster = FAT16GetNextCluster; DeviceExt->FindAndMarkAvailableCluster = FAT16FindAndMarkAvailableCluster; DeviceExt->WriteCluster = FAT16WriteCluster; DeviceExt->CleanShutBitMask = 0x8000; break; case FAT32: case FATX32: DeviceExt->GetNextCluster = FAT32GetNextCluster; DeviceExt->FindAndMarkAvailableCluster = FAT32FindAndMarkAvailableCluster; DeviceExt->WriteCluster = FAT32WriteCluster; DeviceExt->CleanShutBitMask = 0x80000000; break; } if (DeviceExt->FatInfo.FatType == FATX16 || DeviceExt->FatInfo.FatType == FATX32) { DeviceExt->Flags |= VCB_IS_FATX; DeviceExt->GetNextDirEntry = FATXGetNextDirEntry; DeviceExt->BaseDateYear = 2000; } else { DeviceExt->GetNextDirEntry = FATGetNextDirEntry; DeviceExt->BaseDateYear = 1980; } DeviceExt->StorageDevice = DeviceToMount; DeviceExt->StorageDevice->Vpb->DeviceObject = DeviceObject; DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice; DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED; DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1; DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; DPRINT("FsDeviceObject %p\n", DeviceObject); /* Initialize this resource early ... it's used in VfatCleanup */ ExInitializeResourceLite(&DeviceExt->DirResource); DeviceExt->FATFileObject = IoCreateStreamFileObject(NULL, DeviceExt->StorageDevice); Fcb = vfatNewFCB(DeviceExt, &NameU); if (Fcb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto ByeBye; } Ccb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); if (Ccb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto ByeBye; } RtlZeroMemory(Ccb, sizeof (VFATCCB)); DeviceExt->FATFileObject->FsContext = Fcb; DeviceExt->FATFileObject->FsContext2 = Ccb; DeviceExt->FATFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; DeviceExt->FATFileObject->PrivateCacheMap = NULL; DeviceExt->FATFileObject->Vpb = DeviceObject->Vpb; Fcb->FileObject = DeviceExt->FATFileObject; Fcb->Flags |= FCB_IS_FAT; Fcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector; Fcb->RFCB.ValidDataLength = Fcb->RFCB.FileSize; Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize; CcInitializeCacheMap(DeviceExt->FATFileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), TRUE, &VfatGlobalData->CacheMgrCallbacks, Fcb); DeviceExt->LastAvailableCluster = 2; ExInitializeResourceLite(&DeviceExt->FatResource); InitializeListHead(&DeviceExt->FcbListHead); VolumeFcb = vfatNewFCB(DeviceExt, &VolumeNameU); if (VolumeFcb == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto ByeBye; } VolumeFcb->Flags = FCB_IS_VOLUME; VolumeFcb->RFCB.FileSize.QuadPart = DeviceExt->FatInfo.Sectors * DeviceExt->FatInfo.BytesPerSector; VolumeFcb->RFCB.ValidDataLength = VolumeFcb->RFCB.FileSize; VolumeFcb->RFCB.AllocationSize = VolumeFcb->RFCB.FileSize; DeviceExt->VolumeFcb = VolumeFcb; ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE); InsertHeadList(&VfatGlobalData->VolumeListHead, &DeviceExt->VolumeListEntry); ExReleaseResourceLite(&VfatGlobalData->VolumeListLock); /* read serial number */ DeviceObject->Vpb->SerialNumber = DeviceExt->FatInfo.VolumeID; /* read volume label */ ReadVolumeLabel(DeviceExt, DeviceObject->Vpb); /* read clean shutdown bit status */ Status = GetNextCluster(DeviceExt, 1, &eocMark); if (NT_SUCCESS(Status)) { if (eocMark & DeviceExt->CleanShutBitMask) { /* unset clean shutdown bit */ eocMark &= ~DeviceExt->CleanShutBitMask; WriteCluster(DeviceExt, 1, eocMark); VolumeFcb->Flags |= VCB_CLEAR_DIRTY; } } VolumeFcb->Flags |= VCB_IS_DIRTY; FsRtlNotifyVolumeEvent(DeviceExt->FATFileObject, FSRTL_VOLUME_MOUNT); Status = STATUS_SUCCESS; ByeBye: if (!NT_SUCCESS(Status)) { // cleanup if (DeviceExt && DeviceExt->FATFileObject) ObDereferenceObject (DeviceExt->FATFileObject); if (Fcb) vfatDestroyFCB(Fcb); if (Ccb) vfatDestroyCCB(Ccb); if (DeviceObject) IoDeleteDevice(DeviceObject); if (VolumeFcb) vfatDestroyFCB(VolumeFcb); } return Status; }
USHORT usWriteEAS(PVOLINFO pVolInfo, ULONG ulDirCluster, PSZ pszFileName, PFEALIST pFEAL) { ULONG ulCluster, ulNextCluster; PBYTE pszEAName; PBYTE pWrite; USHORT rc; USHORT usClustersNeeded; DIRENTRY DirEntry; DIRENTRY DirNew; BOOL fCritical; PFEA pFea, pFeaEnd; if (pFEAL->cbList > MAX_EA_SIZE) return ERROR_EA_LIST_TOO_LONG; rc = GetEASName(pVolInfo, ulDirCluster, pszFileName, &pszEAName); if (rc) return rc; usClustersNeeded = (USHORT)pFEAL->cbList / pVolInfo->usClusterSize; if (pFEAL->cbList % pVolInfo->usClusterSize) usClustersNeeded++; ulCluster = FindPathCluster(pVolInfo, ulDirCluster, pszEAName, &DirEntry, NULL); if (!ulCluster || ulCluster == FAT_EOF) { BOOL fNew = FALSE; if (ulCluster == FAT_EOF) { fNew = TRUE; memset(&DirNew, 0, sizeof DirNew); DirNew.bAttr = FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY; DirNew.ulFileSize = pFEAL->cbList; } else memcpy(&DirNew, &DirEntry, sizeof DirEntry); ulCluster = MakeFatChain(pVolInfo, FAT_EOF, (ULONG)usClustersNeeded, NULL); if (ulCluster == FAT_EOF) { free(pszEAName); return ERROR_DISK_FULL; } DirNew.wCluster = LOUSHORT(ulCluster); DirNew.wClusterHigh = HIUSHORT(ulCluster); if (fNew) rc = MakeDirEntry(pVolInfo, ulDirCluster, &DirNew, pszEAName); else rc = ModifyDirectory(pVolInfo, ulDirCluster, MODIFY_DIR_UPDATE, &DirEntry, &DirNew, NULL, 0); if (rc) { free(pszEAName); return rc; } } else { memcpy(&DirNew, &DirEntry, sizeof (DIRENTRY)); DirNew.ulFileSize = pFEAL->cbList; rc = ModifyDirectory(pVolInfo, ulDirCluster, MODIFY_DIR_UPDATE, &DirEntry, &DirNew, NULL, 0); if (rc) { free(pszEAName); return rc; } } free(pszEAName); pWrite = (PBYTE)pFEAL; ulNextCluster = FAT_EOF; while (usClustersNeeded) { ulNextCluster = GetNextCluster(pVolInfo, ulCluster); if (!ulNextCluster) ulNextCluster = FAT_EOF; rc = WriteCluster(pVolInfo, ulCluster, pWrite, 0); if (rc) return rc; usClustersNeeded --; pWrite += pVolInfo->usClusterSize; if (usClustersNeeded) { if (ulNextCluster == FAT_EOF) ulCluster = MakeFatChain(pVolInfo, ulCluster, (ULONG)usClustersNeeded, NULL); else ulCluster = ulNextCluster; if (ulCluster == FAT_EOF) return ERROR_DISK_FULL; } } if (ulNextCluster != FAT_EOF) { SetNextCluster(pVolInfo, ulCluster, FAT_EOF); DeleteFatChain(pVolInfo, ulNextCluster); } pFea = pFEAL->list; pFeaEnd = (PFEA)((PBYTE)pFEAL + pFEAL->cbList); fCritical = FALSE; while (pFea < pFeaEnd) { if (pFea->fEA & FEA_NEEDEA) fCritical = TRUE; pFea = (PFEA)((PBYTE)pFea + sizeof (FEA) + (USHORT)pFea->cbName + 1 + pFea->cbValue); } if (fCritical) rc = MarkFileEAS(pVolInfo, ulDirCluster, pszFileName, FILE_HAS_CRITICAL_EAS); else rc = MarkFileEAS(pVolInfo, ulDirCluster, pszFileName, FILE_HAS_EAS); return rc; }
//Find one empty short directory entry in a cluster chain start from dwStartCluster, //and save the short entry pointed by pfse into this entry.If can not find a free one //in the whole cluster chain,then append a free cluster in the chain and save it. BOOL CreateDirEntry(__FAT32_FS* pFat32Fs,DWORD dwStartCluster,__FAT32_SHORTENTRY* pDirEntry) { __FAT32_SHORTENTRY DirEntry; __FAT32_SHORTENTRY* pfse = NULL; DWORD dwSector = 0; DWORD dwCurrCluster = 0; DWORD dwNextCluster = 0; BYTE* pBuffer = NULL; CHAR DirName[13] = {0}; DWORD i; BOOL bFind = FALSE; BOOL bResult = FALSE; if((NULL == pFat32Fs) || (dwStartCluster < 2) || IS_EOC(dwStartCluster) || (NULL == pDirEntry)) { goto __TERMINAL; } if(!ConvertName(pDirEntry,(BYTE*)&DirName[0])) { goto __TERMINAL; } //Check if the directory to be created has already in directory. if(GetShortEntry(pFat32Fs,dwStartCluster,DirName,&DirEntry,NULL,NULL)) //Directory already exists. { goto __TERMINAL; } pBuffer = (BYTE*)LocalAlloc(LPTR,pFat32Fs->dwClusterSize); if(NULL == pBuffer) { goto __TERMINAL; } //Try to find a free directory entry in the given directory,if can not find,then //allocate a free cluster,append it to the given directory. dwNextCluster = dwStartCluster; while(!IS_EOC(dwNextCluster)) { dwCurrCluster = dwNextCluster; dwSector = GetClusterSector(pFat32Fs,dwCurrCluster); if(0 == dwSector) { //PrintLine(" In CreateDirEntry,Condition 2"); goto __TERMINAL; } if(!ReadDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+dwSector, pFat32Fs->SectorPerClus,pBuffer)) { //PrintLine(" In CreateDirEntry,Condition 3"); goto __TERMINAL; } //Search this cluster from begin. pfse = (__FAT32_SHORTENTRY*)pBuffer; for(i = 0;i < pFat32Fs->dwClusterSize / sizeof(__FAT32_SHORTENTRY);i++) { if((0 == pfse->FileName[0]) || (0xE5 == (BYTE)pfse->FileName[0])) //Find a free slot. { bFind = TRUE; break; } pfse ++; } if(bFind) //Find a free directory entry,no need to check further. { break; } //Can not find a free directory slot,try to search next cluster. if(!GetNextCluster(pFat32Fs,&dwNextCluster)) { //PrintLine(" In CreateDirEntry,Condition 4"); goto __TERMINAL; } } if(bFind) //Has found a free directory slot. { memcpy((char*)pfse,(const char*)pDirEntry,sizeof(__FAT32_SHORTENTRY)); if(!WriteDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+dwSector,pFat32Fs->SectorPerClus,pBuffer)) { goto __TERMINAL; } } else //Can not find a free slot,allocate a new cluster for parent directory. { if(!AppendClusterToChain(pFat32Fs,&dwCurrCluster)) { goto __TERMINAL; } ZeroMemory(pBuffer,pFat32Fs->dwClusterSize); memcpy((char*)pBuffer,(const char*)pDirEntry,sizeof(__FAT32_SHORTENTRY)); dwSector = GetClusterSector(pFat32Fs,dwCurrCluster); if(!WriteDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+dwSector,pFat32Fs->SectorPerClus,pBuffer)) { goto __TERMINAL; } } bResult = TRUE; __TERMINAL: if(pBuffer) { LocalFree(pBuffer); } return bResult; }
NTSTATUS NTAPI VfatShutdown(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS Status; PLIST_ENTRY ListEntry; PDEVICE_EXTENSION DeviceExt; ULONG eocMark; DPRINT("VfatShutdown(DeviceObject %p, Irp %p)\n",DeviceObject, Irp); FsRtlEnterFileSystem(); /* FIXME: block new mount requests */ if (DeviceObject == VfatGlobalData->DeviceObject) { Irp->IoStatus.Status = STATUS_SUCCESS; ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE); ListEntry = VfatGlobalData->VolumeListHead.Flink; while (ListEntry != &VfatGlobalData->VolumeListHead) { DeviceExt = CONTAINING_RECORD(ListEntry, VCB, VolumeListEntry); ListEntry = ListEntry->Flink; ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE); if (DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY) { /* set clean shutdown bit */ Status = GetNextCluster(DeviceExt, 1, &eocMark); if (NT_SUCCESS(Status)) { eocMark |= DeviceExt->CleanShutBitMask; if (NT_SUCCESS(WriteCluster(DeviceExt, 1, eocMark))) DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY; } } Status = VfatFlushVolume(DeviceExt, DeviceExt->VolumeFcb); if (NT_SUCCESS(Status)) { Status = VfatDiskShutDown(DeviceExt); if (!NT_SUCCESS(Status)) DPRINT1("VfatDiskShutDown failed, status = %x\n", Status); } else { DPRINT1("VfatFlushVolume failed, status = %x\n", Status); } ExReleaseResourceLite(&DeviceExt->DirResource); /* FIXME: Unmount the logical volume */ if (!NT_SUCCESS(Status)) Irp->IoStatus.Status = Status; } ExReleaseResourceLite(&VfatGlobalData->VolumeListLock); /* FIXME: Free all global acquired resources */ Status = Irp->IoStatus.Status; } else { Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Status = STATUS_INVALID_DEVICE_REQUEST; } Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); FsRtlExitFileSystem(); return(Status); }
BOOL DumpDirectory(PDRIVEINFO pDrive, ULONG ulDirCluster, PSZ pszPath) { static BYTE szLongName[512]; int iIndex; PDIRENTRY pDir; PBYTE pbCluster; PBYTE pbPath; USHORT usClusters; ULONG ulCluster; ULONG ulBytesNeeded; BYTE _huge * p; PDIRENTRY pEnd; BYTE bCheckSum, bCheck; ULONG ulClustersNeeded; ULONG ulClustersUsed; ULONG ulEntries; static BYTE szShortName[13]; if (!ulDirCluster) { printf("ERROR: Cluster for %s is 0!\n", pszPath); return TRUE; } if (ulDirCluster == pDrive->bpb.RootDirStrtClus) { PULONG pulCluster; ReadFATSector(pDrive, 0); pulCluster = (PULONG)pDrive->pbFATSector; printf("MEDIA BYTES in FAT: %8.8lX\n", *pulCluster); pulCluster = (PULONG)pDrive->pbFATSector + 1; printf("DiskStatus: %8.8lX\n", *pulCluster); // vDumpSector(pDrive->pbFATSector); } //pDrive->ulTotalDirs++; pbPath = malloc(512); usClusters = GetClusterCount(pDrive, ulDirCluster); ulTotalClusters += usClusters; if (fDetailed > 2) printf("\n\nDirectory of %s (%u clusters)\n\n", pszPath, usClusters); ulBytesNeeded = (ULONG)pDrive->bpb.SectorsPerCluster * (ULONG)pDrive->bpb.BytesPerSector * usClusters; pbCluster = calloc(usClusters, pDrive->bpb.SectorsPerCluster * pDrive->bpb.BytesPerSector); if (!pbCluster) { printf("ERROR:Not enough memory!\n"); return FALSE; } ulCluster = ulDirCluster; p = pbCluster; while (ulCluster != FAT_EOF) { ReadCluster(pDrive, ulCluster); memcpy(p, pDrive->pbCluster, pDrive->bpb.SectorsPerCluster * pDrive->bpb.BytesPerSector); ulCluster = GetNextCluster(pDrive, ulCluster); p += pDrive->bpb.SectorsPerCluster * pDrive->bpb.BytesPerSector; } memset(szLongName, 0, sizeof szLongName); pDir = (PDIRENTRY)pbCluster; pEnd = (PDIRENTRY)(pbCluster + ulBytesNeeded - sizeof (DIRENTRY)); ulEntries = 0; bCheck = 0; while (pDir <= pEnd) { if (fDetailed > 3) { ULONG ulOffset = (PBYTE)pDir - pbCluster; if (ulOffset && !(ulOffset % 4096)) printf("-------- NEXT CLUSTER ----------\n"); } if (pDir->bFileName[0] && pDir->bFileName[0] != 0xE5) { if (pDir->bAttr == FILE_LONGNAME) { if (fDetailed > 3) { printf("(longname)\n"); vDumpDirEntry(pDir); } if (strlen(szLongName) && bCheck != pDir->bReserved) { printf("A lost long filename was found: %s\n", szLongName); memset(szLongName, 0, sizeof szLongName); } bCheck = pDir->bReserved; fGetLongName(pDir, szLongName, sizeof szLongName); } else { bCheckSum = 0; for (iIndex = 0; iIndex < 11; iIndex++) { if (bCheckSum & 0x01) { bCheckSum >>=1; bCheckSum |= 0x80; } else bCheckSum >>=1; bCheckSum += pDir->bFileName[iIndex]; } if (strlen(szLongName) && bCheck != bCheckSum) { printf("The longname %s does not belong to %s\\%s\n", szLongName, pszPath, MakeName(pDir, szShortName, sizeof szShortName)); memset(szLongName, 0, sizeof szLongName); } if (fDetailed > 2) { printf("%-8.8s.%-3.3s %2.2X ", pDir->bFileName, pDir->bExtention, pDir->bAttr); if (pDir->bAttr & FILE_DIRECTORY) printf("<DIR> "); else printf("%10lu ", pDir->ulFileSize); printf("%8.8lX ", MAKEP(pDir->wClusterHigh, pDir->wCluster)); if (pDir->fEAS) printf("%2.2X ", pDir->fEAS); else printf(" "); printf("%s\n", szLongName); } if (!(pDir->bAttr & FILE_DIRECTORY)) { ulClustersNeeded = pDir->ulFileSize / pDrive->usClusterSize + (pDir->ulFileSize % pDrive->usClusterSize ? 1:0); ulClustersUsed = GetClusterCount(pDrive,(ULONG)pDir->wClusterHigh * 0x10000 + pDir->wCluster); ulTotalClusters += ulClustersUsed; if (ulClustersNeeded != ulClustersUsed) { printf("File allocation error detected for %s\\%s\n", pszPath, MakeName(pDir, szShortName, sizeof szShortName)); printf("%lu clusters needed, %lu clusters allocated\n", ulClustersNeeded, ulClustersUsed); } } memset(szLongName, 0, sizeof szLongName); } ulEntries++; }
DWORD WriteFileToVhd(__FAT32_FS* pFat32Fs,__FAT32_FILE* pFat32File,LPCSTR pSrcFile) { __FAT32_SHORTENTRY* pFat32Entry = NULL; HANDLE hSrcFile = NULL; BYTE* pClusBuffer = NULL; BYTE* pStart = NULL; DWORD dwCurrPos = 0; DWORD dwSector = 0; DWORD dwNextClus = 0; DWORD dwWriteSize = 0; DWORD dwFirstCluster = 0; DWORD dwOnceSize = 0; DWORD dwWritten = 0; //Record the written size. hSrcFile = CreateFileA(pSrcFile,GENERIC_READ,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0); if(hSrcFile == INVALID_HANDLE_VALUE) { return S_OK; } dwWriteSize = GetFileSize(hSrcFile,NULL); pClusBuffer = (BYTE*)LocalAlloc(LPTR,pFat32Fs->dwClusterSize); if(NULL == pClusBuffer) //Can not allocate buffer. { goto __TERMINAL; } dwCurrPos = pFat32File->dwCurrPos; dwNextClus = pFat32File->dwCurrClusNum; //if file null,first alloc a Cluster if(dwNextClus == 0 && GetFreeCluster(pFat32Fs,0,&dwNextClus)) { pFat32File->dwCurrClusNum = dwNextClus; pFat32File->dwStartClusNum = dwNextClus; dwFirstCluster = dwNextClus; } dwSector = GetClusterSector(pFat32Fs,dwNextClus); if(0 == dwSector) { goto __TERMINAL; } //Read the current cluster. if(!ReadDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+ dwSector,pFat32Fs->SectorPerClus, pClusBuffer)) { goto __TERMINAL; } while(dwWriteSize > 0) { DWORD dwRead = 0; pStart = pClusBuffer + pFat32File->dwClusOffset; dwOnceSize = pFat32Fs->dwClusterSize - pFat32File->dwClusOffset; if(dwOnceSize > dwWriteSize) { dwOnceSize = dwWriteSize; } //memcpy(pStart,pBuffer,dwOnceSize); ReadFile(hSrcFile,pStart,dwOnceSize,&dwRead,NULL); //Now write the cluster into memory. if(!WriteDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+dwSector,pFat32Fs->SectorPerClus,pClusBuffer)) { goto __TERMINAL; } //Adjust file object's status. pFat32File->dwClusOffset += dwOnceSize; pFat32File->dwCurrPos += dwOnceSize; //2014.9.28 modified by tywind if(pFat32File->dwCurrPos >= pFat32File->dwFileSize) { pFat32File->dwFileSize = pFat32File->dwCurrPos; } if(0 == (pFat32File->dwClusOffset % pFat32Fs->dwClusterSize)) { dwNextClus = pFat32File->dwCurrClusNum; if(!GetNextCluster(pFat32Fs,&dwNextClus)) { goto __TERMINAL; } if(IS_EOC(dwNextClus)) //Reach the end of file,so extend file. { if(!AppendClusterToChain(pFat32Fs,&pFat32File->dwCurrClusNum)) { goto __TERMINAL; } dwNextClus = pFat32File->dwCurrClusNum; } pFat32File->dwCurrClusNum = dwNextClus; pFat32File->dwClusOffset = 0; //Update dwSector to corespond current cluster. dwSector = GetClusterSector(pFat32Fs,dwNextClus); if(0 == dwSector) { goto __TERMINAL; } } //Adjust the buffer position and local control variables. dwWritten += dwOnceSize; dwWriteSize -= dwOnceSize; if(0 == dwWriteSize) //Write over. { break; } } //Now update the file's directory entry. dwSector = GetClusterSector(pFat32Fs,pFat32File->dwParentClus); if(0 == dwSector) { goto __TERMINAL; } if(!ReadDeviceSector(pFat32Fs->pPartition,pFat32Fs->dwPartitionSatrt+dwSector,pFat32Fs->SectorPerClus,pClusBuffer)) { goto __TERMINAL; } pFat32Entry = (__FAT32_SHORTENTRY*)(pClusBuffer + pFat32File->dwParentOffset); //modify file First Cluster index if(dwFirstCluster > 0 ) { pFat32Entry->wFirstClusHi = (WORD)(dwFirstCluster >> 16); pFat32Entry->wFirstClusLow = (WORD)(dwFirstCluster&0x0000FFFF); }
//Find one empty short directory entry in a cluster chain start from dwStartCluster, //and save the short entry pointed by pfse into this entry.If can not find a free one //in the whole cluster chain,then append a free cluster in the chain and save it. BOOL CreateDirEntry(__FAT32_FS* pFat32Fs,DWORD dwStartCluster,__FAT32_SHORTENTRY* pDirEntry) { __FAT32_SHORTENTRY DirEntry; __FAT32_SHORTENTRY* pfse = NULL; DWORD dwSector = 0; DWORD dwCurrCluster = 0; DWORD dwNextCluster = 0; BYTE* pBuffer = NULL; CHAR DirName[13] = {0}; DWORD i; BOOL bFind = FALSE; BOOL bResult = FALSE; if((NULL == pFat32Fs) || (dwStartCluster < 2) || IS_EOC(dwStartCluster) || (NULL == pDirEntry)) { PrintLine(" In CreateDirEntry,Condition 0"); goto __TERMINAL; } if(!ConvertName(pDirEntry,(BYTE*)&DirName[0])) { PrintLine(" In CreateDirEntry,Condition 1"); goto __TERMINAL; } //Check if the directory to be created has already in directory. if(GetShortEntry(pFat32Fs,dwStartCluster,DirName,&DirEntry,NULL,NULL)) //Directory already exists. { PrintLine(" In CreateDirEntry: The specified directory already exist."); goto __TERMINAL; } pBuffer = (BYTE*)KMemAlloc(pFat32Fs->dwClusterSize,KMEM_SIZE_TYPE_ANY); if(NULL == pBuffer) { PrintLine(" In CreateDirEntry,can not allocate memory for temporary buffer."); goto __TERMINAL; } //Try to find a free directory entry in the given directory,if can not find,then //allocate a free cluster,append it to the given directory. dwNextCluster = dwStartCluster; while(!IS_EOC(dwNextCluster)) { dwCurrCluster = dwNextCluster; dwSector = GetClusterSector(pFat32Fs,dwCurrCluster); if(0 == dwSector) { PrintLine(" In CreateDirEntry,Condition 2"); goto __TERMINAL; } if(!ReadDeviceSector((__COMMON_OBJECT*)pFat32Fs->pPartition, dwSector, pFat32Fs->SectorPerClus, pBuffer)) { PrintLine(" In CreateDirEntry,Condition 3"); goto __TERMINAL; } //Search this cluster from begin. pfse = (__FAT32_SHORTENTRY*)pBuffer; for(i = 0;i < pFat32Fs->dwClusterSize / sizeof(__FAT32_SHORTENTRY);i++) { if((0 == pfse->FileName[0]) || ((BYTE)0xE5 == pfse->FileName[0])) //Find a free slot. { bFind = TRUE; break; } pfse ++; } if(bFind) //Find a free directory entry,no need to check further. { break; } //Can not find a free directory slot,try to search next cluster. if(!GetNextCluster(pFat32Fs,&dwNextCluster)) { PrintLine(" In CreateDirEntry,Condition 4"); goto __TERMINAL; } } if(bFind) //Has found a free directory slot. { memcpy((char*)pfse,(const char*)pDirEntry,sizeof(__FAT32_SHORTENTRY)); if(!WriteDeviceSector((__COMMON_OBJECT*)pFat32Fs->pPartition, dwSector, pFat32Fs->SectorPerClus, pBuffer)) { PrintLine(" In CreateDirEntry,Condition 5"); goto __TERMINAL; } } else //Can not find a free slot,allocate a new cluster for parent directory. { if(!AppendClusterToChain(pFat32Fs,&dwCurrCluster)) { PrintLine(" In CreateDirEntry: Can not append a free cluster to this dir."); goto __TERMINAL; } memzero(pBuffer,pFat32Fs->dwClusterSize); memcpy((char*)pBuffer,(const char*)pDirEntry,sizeof(__FAT32_SHORTENTRY)); dwSector = GetClusterSector(pFat32Fs,dwCurrCluster); if(!WriteDeviceSector((__COMMON_OBJECT*)pFat32Fs->pPartition, dwSector, pFat32Fs->SectorPerClus, pBuffer)) { PrintLine(" In CreateDirEntry,Condition 6"); goto __TERMINAL; } } /* _hx_sprintf(pBuffer,"In CreateDirEntry: dwSector = %d,dwCurrCluster = %d,offset = %d", dwSector, dwCurrCluster, (BYTE*)pfse - pBuffer); PrintLine(pBuffer);*/ bResult = TRUE; __TERMINAL: if(pBuffer) { KMemFree(pBuffer,KMEM_SIZE_TYPE_ANY,0); } return bResult; }
BOOL GetShortEntry(__FAT32_FS* pFat32Fs,DWORD dwStartCluster,CHAR* pFileName,__FAT32_SHORTENTRY* pShortEntry, DWORD* pDirClus,DWORD* pDirOffset) { BOOL bResult = FALSE; __FAT32_SHORTENTRY* pfse = NULL; BYTE* pBuffer = NULL; DWORD dwCurrClus = 0; DWORD dwSector = 0; BYTE FileName[13]; int i; if((NULL == pFat32Fs) || (NULL == pFileName) || (pShortEntry == pfse)) { goto __TERMINAL; } //Create local buffer to contain one cluster. pBuffer = (BYTE*)LocalAlloc(LPTR,pFat32Fs->SectorPerClus * pFat32Fs->dwBytePerSector); if(NULL == pBuffer) { goto __TERMINAL; } dwCurrClus = dwStartCluster; while(!IS_EOC(dwCurrClus)) //Main loop to check the root directory. { dwSector = GetClusterSector(pFat32Fs,dwCurrClus); if(0 == dwSector) //Fatal error. { //PrintLine(" In GetShortEntry: Can not get cluster sector."); goto __TERMINAL; } if(!ReadDeviceSector(pFat32Fs->pPartition, pFat32Fs->dwPartitionSatrt+dwSector, pFat32Fs->SectorPerClus, pBuffer)) //Can not read the appropriate sector(s). { //PrintLine(" In GetShortEntry: Can not read sector from device."); goto __TERMINAL; } //Now check the root directory to seek the volume ID entry. pfse = (__FAT32_SHORTENTRY*)pBuffer; for(i = 0;i < pFat32Fs->SectorPerClus * 16;i ++) { if(0xE5 == (BYTE)pfse->FileName[0]) //Empty entry. { pfse += 1; //Seek to the next entry. continue; } if(0 == pfse->FileName[0]) //All rest part is zero,no need to check futher. { break; } if(FILE_ATTR_LONGNAME == pfse->FileAttributes) //Long file name entry. { pfse += 1; continue; } if(FILE_ATTR_VOLUMEID & pfse->FileAttributes) //Volume label entry. { pfse += 1; continue; } if(ConvertName(pfse,FileName)) //Can not convert to regular file name string. { if(strcmpi((CHAR*)pFileName,(CHAR*)&FileName[0]) == 0) //Found. { memcpy((char*)pShortEntry,(const char*)pfse,sizeof(__FAT32_SHORTENTRY)); if(pDirClus) { *pDirClus = dwCurrClus; } if(pDirOffset) { *pDirOffset = (BYTE*)pfse - pBuffer; } bResult = TRUE; goto __TERMINAL; } } pfse += 1; } if(!GetNextCluster(pFat32Fs,&dwCurrClus)) { break; } } __TERMINAL: if(pBuffer) { LocalFree(pBuffer); } return bResult; }
static NTSTATUS VfatDismountVolume( PVFAT_IRP_CONTEXT IrpContext) { PDEVICE_EXTENSION DeviceExt; PLIST_ENTRY NextEntry; PVFATFCB Fcb; PFILE_OBJECT FileObject; ULONG eocMark; NTSTATUS Status; DPRINT("VfatDismountVolume(%p)\n", IrpContext); DeviceExt = IrpContext->DeviceExt; FileObject = IrpContext->FileObject; /* We HAVE to be locked. Windows also allows dismount with no lock * but we're here mainly for 1st stage, so KISS */ if (!(DeviceExt->Flags & VCB_VOLUME_LOCKED)) { return STATUS_ACCESS_DENIED; } /* Race condition? */ if (DeviceExt->Flags & VCB_DISMOUNT_PENDING) { return STATUS_VOLUME_DISMOUNTED; } /* Notify we'll dismount. Pass that point there's no reason we fail */ FsRtlNotifyVolumeEvent(IrpContext->Stack->FileObject, FSRTL_VOLUME_DISMOUNT); ExAcquireResourceExclusiveLite(&DeviceExt->FatResource, TRUE); if (DeviceExt->VolumeFcb->Flags & VCB_CLEAR_DIRTY) { /* Set clean shutdown bit */ Status = GetNextCluster(DeviceExt, 1, &eocMark); if (NT_SUCCESS(Status)) { eocMark |= DeviceExt->CleanShutBitMask; if (NT_SUCCESS(WriteCluster(DeviceExt, 1, eocMark))) DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY; } } /* Flush volume & files */ VfatFlushVolume(DeviceExt, (PVFATFCB)FileObject->FsContext); /* Rebrowse the FCB in order to free them now */ while (!IsListEmpty(&DeviceExt->FcbListHead)) { NextEntry = RemoveHeadList(&DeviceExt->FcbListHead); Fcb = CONTAINING_RECORD(NextEntry, VFATFCB, FcbListEntry); vfatDestroyFCB(Fcb); } /* Mark we're being dismounted */ DeviceExt->Flags |= VCB_DISMOUNT_PENDING; #ifndef ENABLE_SWAPOUT IrpContext->DeviceObject->Vpb->Flags &= ~VPB_MOUNTED; #endif ExReleaseResourceLite(&DeviceExt->FatResource); /* Release a few resources and quit, we're done */ ExDeleteResourceLite(&DeviceExt->DirResource); ExDeleteResourceLite(&DeviceExt->FatResource); ObDereferenceObject(DeviceExt->FATFileObject); return STATUS_SUCCESS; }