📄 fat.c
字号:
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#include <debug.h>
ULONG BytesPerSector; /* Number of bytes per sector */
ULONG SectorsPerCluster; /* Number of sectors per cluster */
ULONG FatVolumeStartSector; /* Absolute starting sector of the partition */
ULONG FatSectorStart; /* Starting sector of 1st FAT table */
ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
ULONG NumberOfFats; /* Number of FAT tables */
ULONG SectorsPerFat; /* Sectors per FAT table */
ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */
ULONG RootDirSectors; /* Number of sectors of the root directory (non-fat32) */
ULONG RootDirStartCluster; /* Starting cluster number of the root directory (fat32 only) */
ULONG DataSectorStart; /* Starting sector of the data area */
ULONG FatType = 0; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
ULONG FatDriveNumber = 0;
BOOLEAN FatOpenVolume(ULONG DriveNumber, ULONG VolumeStartSector, ULONG PartitionSectorCount)
{
char ErrMsg[80];
ULONG FatSize;
PFAT_BOOTSECTOR FatVolumeBootSector;
PFAT32_BOOTSECTOR Fat32VolumeBootSector;
PFATX_BOOTSECTOR FatXVolumeBootSector;
DbgPrint((DPRINT_FILESYSTEM, "FatOpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
// Store the drive number
FatDriveNumber = DriveNumber;
//
// Allocate the memory to hold the boot sector
//
FatVolumeBootSector = (PFAT_BOOTSECTOR) MmAllocateMemory(512);
Fat32VolumeBootSector = (PFAT32_BOOTSECTOR) FatVolumeBootSector;
FatXVolumeBootSector = (PFATX_BOOTSECTOR) FatVolumeBootSector;
//
// Make sure we got the memory
//
if (FatVolumeBootSector == NULL)
{
FileSystemError("Out of memory.");
return FALSE;
}
// Now try to read the boot sector
// If this fails then abort
if (!MachDiskReadLogicalSectors(DriveNumber, VolumeStartSector, 1, (PVOID)DISKREADBUFFER))
{
MmFreeMemory(FatVolumeBootSector);
return FALSE;
}
RtlCopyMemory(FatVolumeBootSector, (PVOID)DISKREADBUFFER, 512);
// Get the FAT type
FatType = FatDetermineFatType(FatVolumeBootSector, PartitionSectorCount);
DbgPrint((DPRINT_FILESYSTEM, "Dumping boot sector:\n"));
if (ISFATX(FatType))
{
DbgPrint((DPRINT_FILESYSTEM, "sizeof(FATX_BOOTSECTOR) = 0x%x.\n", sizeof(FATX_BOOTSECTOR)));
DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c.\n", FatXVolumeBootSector->FileSystemType[0], FatXVolumeBootSector->FileSystemType[1], FatXVolumeBootSector->FileSystemType[2], FatXVolumeBootSector->FileSystemType[3]));
DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatXVolumeBootSector->VolumeSerialNumber));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatXVolumeBootSector->SectorsPerCluster));
DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatXVolumeBootSector->NumberOfFats));
DbgPrint((DPRINT_FILESYSTEM, "Unknown: 0x%x\n", FatXVolumeBootSector->Unknown));
DbgPrint((DPRINT_FILESYSTEM, "FatType %s\n", FatType == FATX16 ? "FATX16" : "FATX32"));
}
else if (FatType == FAT32)
{
DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT32_BOOTSECTOR) = 0x%x.\n", sizeof(FAT32_BOOTSECTOR)));
DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", Fat32VolumeBootSector->JumpBoot[0], Fat32VolumeBootSector->JumpBoot[1], Fat32VolumeBootSector->JumpBoot[2]));
DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->OemName[0], Fat32VolumeBootSector->OemName[1], Fat32VolumeBootSector->OemName[2], Fat32VolumeBootSector->OemName[3], Fat32VolumeBootSector->OemName[4], Fat32VolumeBootSector->OemName[5], Fat32VolumeBootSector->OemName[6], Fat32VolumeBootSector->OemName[7]));
DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", Fat32VolumeBootSector->BytesPerSector));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", Fat32VolumeBootSector->SectorsPerCluster));
DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", Fat32VolumeBootSector->ReservedSectors));
DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", Fat32VolumeBootSector->NumberOfFats));
DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", Fat32VolumeBootSector->RootDirEntries));
DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", Fat32VolumeBootSector->TotalSectors));
DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", Fat32VolumeBootSector->MediaDescriptor));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", Fat32VolumeBootSector->SectorsPerFat));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", Fat32VolumeBootSector->SectorsPerTrack));
DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", Fat32VolumeBootSector->NumberOfHeads));
DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", Fat32VolumeBootSector->HiddenSectors));
DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", Fat32VolumeBootSector->TotalSectorsBig));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFatBig: %d\n", Fat32VolumeBootSector->SectorsPerFatBig));
DbgPrint((DPRINT_FILESYSTEM, "ExtendedFlags: 0x%x\n", Fat32VolumeBootSector->ExtendedFlags));
DbgPrint((DPRINT_FILESYSTEM, "FileSystemVersion: 0x%x\n", Fat32VolumeBootSector->FileSystemVersion));
DbgPrint((DPRINT_FILESYSTEM, "RootDirStartCluster: %d\n", Fat32VolumeBootSector->RootDirStartCluster));
DbgPrint((DPRINT_FILESYSTEM, "FsInfo: %d\n", Fat32VolumeBootSector->FsInfo));
DbgPrint((DPRINT_FILESYSTEM, "BackupBootSector: %d\n", Fat32VolumeBootSector->BackupBootSector));
DbgPrint((DPRINT_FILESYSTEM, "Reserved: 0x%x\n", Fat32VolumeBootSector->Reserved));
DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", Fat32VolumeBootSector->DriveNumber));
DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", Fat32VolumeBootSector->Reserved1));
DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", Fat32VolumeBootSector->BootSignature));
DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", Fat32VolumeBootSector->VolumeSerialNumber));
DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->VolumeLabel[0], Fat32VolumeBootSector->VolumeLabel[1], Fat32VolumeBootSector->VolumeLabel[2], Fat32VolumeBootSector->VolumeLabel[3], Fat32VolumeBootSector->VolumeLabel[4], Fat32VolumeBootSector->VolumeLabel[5], Fat32VolumeBootSector->VolumeLabel[6], Fat32VolumeBootSector->VolumeLabel[7], Fat32VolumeBootSector->VolumeLabel[8], Fat32VolumeBootSector->VolumeLabel[9], Fat32VolumeBootSector->VolumeLabel[10]));
DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", Fat32VolumeBootSector->FileSystemType[0], Fat32VolumeBootSector->FileSystemType[1], Fat32VolumeBootSector->FileSystemType[2], Fat32VolumeBootSector->FileSystemType[3], Fat32VolumeBootSector->FileSystemType[4], Fat32VolumeBootSector->FileSystemType[5], Fat32VolumeBootSector->FileSystemType[6], Fat32VolumeBootSector->FileSystemType[7]));
DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", Fat32VolumeBootSector->BootSectorMagic));
}
else
{
DbgPrint((DPRINT_FILESYSTEM, "sizeof(FAT_BOOTSECTOR) = 0x%x.\n", sizeof(FAT_BOOTSECTOR)));
DbgPrint((DPRINT_FILESYSTEM, "JumpBoot: 0x%x 0x%x 0x%x\n", FatVolumeBootSector->JumpBoot[0], FatVolumeBootSector->JumpBoot[1], FatVolumeBootSector->JumpBoot[2]));
DbgPrint((DPRINT_FILESYSTEM, "OemName: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->OemName[0], FatVolumeBootSector->OemName[1], FatVolumeBootSector->OemName[2], FatVolumeBootSector->OemName[3], FatVolumeBootSector->OemName[4], FatVolumeBootSector->OemName[5], FatVolumeBootSector->OemName[6], FatVolumeBootSector->OemName[7]));
DbgPrint((DPRINT_FILESYSTEM, "BytesPerSector: %d\n", FatVolumeBootSector->BytesPerSector));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerCluster: %d\n", FatVolumeBootSector->SectorsPerCluster));
DbgPrint((DPRINT_FILESYSTEM, "ReservedSectors: %d\n", FatVolumeBootSector->ReservedSectors));
DbgPrint((DPRINT_FILESYSTEM, "NumberOfFats: %d\n", FatVolumeBootSector->NumberOfFats));
DbgPrint((DPRINT_FILESYSTEM, "RootDirEntries: %d\n", FatVolumeBootSector->RootDirEntries));
DbgPrint((DPRINT_FILESYSTEM, "TotalSectors: %d\n", FatVolumeBootSector->TotalSectors));
DbgPrint((DPRINT_FILESYSTEM, "MediaDescriptor: 0x%x\n", FatVolumeBootSector->MediaDescriptor));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerFat: %d\n", FatVolumeBootSector->SectorsPerFat));
DbgPrint((DPRINT_FILESYSTEM, "SectorsPerTrack: %d\n", FatVolumeBootSector->SectorsPerTrack));
DbgPrint((DPRINT_FILESYSTEM, "NumberOfHeads: %d\n", FatVolumeBootSector->NumberOfHeads));
DbgPrint((DPRINT_FILESYSTEM, "HiddenSectors: %d\n", FatVolumeBootSector->HiddenSectors));
DbgPrint((DPRINT_FILESYSTEM, "TotalSectorsBig: %d\n", FatVolumeBootSector->TotalSectorsBig));
DbgPrint((DPRINT_FILESYSTEM, "DriveNumber: 0x%x\n", FatVolumeBootSector->DriveNumber));
DbgPrint((DPRINT_FILESYSTEM, "Reserved1: 0x%x\n", FatVolumeBootSector->Reserved1));
DbgPrint((DPRINT_FILESYSTEM, "BootSignature: 0x%x\n", FatVolumeBootSector->BootSignature));
DbgPrint((DPRINT_FILESYSTEM, "VolumeSerialNumber: 0x%x\n", FatVolumeBootSector->VolumeSerialNumber));
DbgPrint((DPRINT_FILESYSTEM, "VolumeLabel: %c%c%c%c%c%c%c%c%c%c%c\n", FatVolumeBootSector->VolumeLabel[0], FatVolumeBootSector->VolumeLabel[1], FatVolumeBootSector->VolumeLabel[2], FatVolumeBootSector->VolumeLabel[3], FatVolumeBootSector->VolumeLabel[4], FatVolumeBootSector->VolumeLabel[5], FatVolumeBootSector->VolumeLabel[6], FatVolumeBootSector->VolumeLabel[7], FatVolumeBootSector->VolumeLabel[8], FatVolumeBootSector->VolumeLabel[9], FatVolumeBootSector->VolumeLabel[10]));
DbgPrint((DPRINT_FILESYSTEM, "FileSystemType: %c%c%c%c%c%c%c%c\n", FatVolumeBootSector->FileSystemType[0], FatVolumeBootSector->FileSystemType[1], FatVolumeBootSector->FileSystemType[2], FatVolumeBootSector->FileSystemType[3], FatVolumeBootSector->FileSystemType[4], FatVolumeBootSector->FileSystemType[5], FatVolumeBootSector->FileSystemType[6], FatVolumeBootSector->FileSystemType[7]));
DbgPrint((DPRINT_FILESYSTEM, "BootSectorMagic: 0x%x\n", FatVolumeBootSector->BootSectorMagic));
}
//
// Set the correct partition offset
//
FatVolumeStartSector = VolumeStartSector;
//
// Check the boot sector magic
//
if (! ISFATX(FatType) && FatVolumeBootSector->BootSectorMagic != 0xaa55)
{
sprintf(ErrMsg, "Invalid boot sector magic on drive 0x%x (expected 0xaa55 found 0x%x)",
DriveNumber, FatVolumeBootSector->BootSectorMagic);
FileSystemError(ErrMsg);
MmFreeMemory(FatVolumeBootSector);
return FALSE;
}
//
// Check the FAT cluster size
// We do not support clusters bigger than 64k
//
if ((ISFATX(FatType) && 64 * 1024 < FatXVolumeBootSector->SectorsPerCluster * 512) ||
(! ISFATX(FatType) && 64 * 1024 < FatVolumeBootSector->SectorsPerCluster * FatVolumeBootSector->BytesPerSector))
{
FileSystemError("This file system has cluster sizes bigger than 64k.\nFreeLoader does not support this.");
MmFreeMemory(FatVolumeBootSector);
return FALSE;
}
//
// Clear our variables
//
FatSectorStart = 0;
ActiveFatSectorStart = 0;
NumberOfFats = 0;
RootDirSectorStart = 0;
DataSectorStart = 0;
SectorsPerFat = 0;
RootDirSectors = 0;
//
// Get the sectors per FAT,
// root directory starting sector,
// and data sector start
//
if (ISFATX(FatType))
{
BytesPerSector = 512;
SectorsPerCluster = FatXVolumeBootSector->SectorsPerCluster;
FatSectorStart = (4096 / BytesPerSector);
ActiveFatSectorStart = FatSectorStart;
NumberOfFats = 1;
FatSize = PartitionSectorCount / SectorsPerCluster *
(FATX16 == FatType ? 2 : 4);
SectorsPerFat = (((FatSize + 4095) / 4096) * 4096) / BytesPerSector;
RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
RootDirSectors = FatXVolumeBootSector->SectorsPerCluster;
DataSectorStart = RootDirSectorStart + RootDirSectors;
}
else if (FatType != FAT32)
{
BytesPerSector = FatVolumeBootSector->BytesPerSector;
SectorsPerCluster = FatVolumeBootSector->SectorsPerCluster;
FatSectorStart = FatVolumeBootSector->ReservedSectors;
ActiveFatSectorStart = FatSectorStart;
NumberOfFats = FatVolumeBootSector->NumberOfFats;
SectorsPerFat = FatVolumeBootSector->SectorsPerFat;
RootDirSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
RootDirSectors = ((FatVolumeBootSector->RootDirEntries * 32) + (BytesPerSector - 1)) / BytesPerSector;
DataSectorStart = RootDirSectorStart + RootDirSectors;
}
else
{
BytesPerSector = Fat32VolumeBootSector->BytesPerSector;
SectorsPerCluster = Fat32VolumeBootSector->SectorsPerCluster;
FatSectorStart = Fat32VolumeBootSector->ReservedSectors;
ActiveFatSectorStart = FatSectorStart +
((Fat32VolumeBootSector->ExtendedFlags & 0x80) ? ((Fat32VolumeBootSector->ExtendedFlags & 0x0f) * Fat32VolumeBootSector->SectorsPerFatBig) : 0);
NumberOfFats = Fat32VolumeBootSector->NumberOfFats;
SectorsPerFat = Fat32VolumeBootSector->SectorsPerFatBig;
RootDirStartCluster = Fat32VolumeBootSector->RootDirStartCluster;
DataSectorStart = FatSectorStart + NumberOfFats * SectorsPerFat;
//
// Check version
// we only work with version 0
//
if (Fat32VolumeBootSector->FileSystemVersion != 0)
{
FileSystemError("FreeLoader is too old to work with this FAT32 filesystem.\nPlease update FreeLoader.");
return FALSE;
}
}
MmFreeMemory(FatVolumeBootSector);
//
// Initialize the disk cache for this drive
//
if (!CacheInitializeDrive(DriveNumber))
{
return FALSE;
}
//
// Force the FAT sectors into the cache
// as long as it is FAT12 or FAT16. FAT32 can
// have a multi-megabyte FAT so we don't want that.
//
if (FatType != FAT32 && FatType != FATX32)
{
if (!CacheForceDiskSectorsIntoCache(DriveNumber, ActiveFatSectorStart, SectorsPerFat))
{
return FALSE;
}
}
return TRUE;
}
ULONG FatDetermineFatType(PFAT_BOOTSECTOR FatBootSector, ULONG PartitionSectorCount)
{
ULONG RootDirSectors;
ULONG DataSectorCount;
ULONG SectorsPerFat;
ULONG TotalSectors;
ULONG CountOfClusters;
PFAT32_BOOTSECTOR Fat32BootSector = (PFAT32_BOOTSECTOR)FatBootSector;
PFATX_BOOTSECTOR FatXBootSector = (PFATX_BOOTSECTOR)FatBootSector;
if (0 == strncmp(FatXBootSector->FileSystemType, "FATX", 4))
{
CountOfClusters = PartitionSectorCount / FatXBootSector->SectorsPerCluster;
if (CountOfClusters < 65525)
{
/* Volume is FATX16 */
return FATX16;
}
else
{
/* Volume is FAT32 */
return FATX32;
}
}
else
{
RootDirSectors = ((FatBootSector->RootDirEntries * 32) + (FatBootSector->BytesPerSector - 1)) / FatBootSector->BytesPerSector;
SectorsPerFat = FatBootSector->SectorsPerFat ? FatBootSector->SectorsPerFat : Fat32BootSector->SectorsPerFatBig;
TotalSectors = FatBootSector->TotalSectors ? FatBootSector->TotalSectors : FatBootSector->TotalSectorsBig;
DataSectorCount = TotalSectors - (FatBootSector->ReservedSectors + (FatBootSector->NumberOfFats * SectorsPerFat) + RootDirSectors);
//mjl
if (FatBootSector->SectorsPerCluster == 0)
CountOfClusters = 0;
else
CountOfClusters = DataSectorCount / FatBootSector->SectorsPerCluster;
if (CountOfClusters < 4085)
{
/* Volume is FAT12 */
return FAT12;
}
else if (CountOfClusters < 65525)
{
/* Volume is FAT16 */
return FAT16;
}
else
{
/* Volume is FAT32 */
return FAT32;
}
}
}
PVOID FatBufferDirectory(ULONG DirectoryStartCluster, ULONG *DirectorySize, BOOLEAN RootDirectory)
{
PVOID DirectoryBuffer;
DbgPrint((DPRINT_FILESYSTEM, "FatBufferDirectory() DirectoryStartCluster = %d RootDirectory = %s\n", DirectoryStartCluster, (RootDirectory ? "TRUE" : "FALSE")));
/*
* For FAT32, the root directory is nothing special. We can treat it the same
* as a subdirectory.
*/
if (RootDirectory && FAT32 == FatType)
{
DirectoryStartCluster = RootDirStartCluster;
RootDirectory = FALSE;
}
//
// Calculate the size of the directory
//
if (RootDirectory)
{
*DirectorySize = RootDirSectors * BytesPerSector;
}
else
{
*DirectorySize = FatCountClustersInChain(DirectoryStartCluster) * SectorsPerCluster * BytesPerSector;
}
//
// Attempt to allocate memory for directory buffer
//
DbgPrint((DPRINT_FILESYSTEM, "Trying to allocate (DirectorySize) %d bytes.\n", *DirectorySize));
DirectoryBuffer = MmAllocateMemory(*DirectorySize);
if (DirectoryBuffer == NULL)
{
return NULL;
}
//
// Now read directory contents into DirectoryBuffer
//
if (RootDirectory)
{
if (!FatReadVolumeSectors(FatDriveNumber, RootDirSectorStart, RootDirSectors, DirectoryBuffer))
{
MmFreeMemory(DirectoryBuffer);
return NULL;
}
}
else
{
if (!FatReadClusterChain(DirectoryStartCluster, 0xFFFFFFFF, DirectoryBuffer))
{
MmFreeMemory(DirectoryBuffer);
return NULL;
}
}
return DirectoryBuffer;
}
BOOLEAN FatSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PFAT_FILE_INFO FatFileInfoPointer)
{
ULONG EntryCount;
ULONG CurrentEntry;
PDIRENTRY DirEntry;
PLFN_DIRENTRY LfnDirEntry;
CHAR LfnNameBuffer[265];
CHAR ShortNameBuffer[20];
ULONG StartCluster;
EntryCount = DirectorySize / sizeof(DIRENTRY);
DbgPrint((DPRINT_FILESYSTEM, "FatSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x EntryCount = %d FileName = %s\n", DirectoryBuffer, EntryCount, FileName));
memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
DirEntry = (PDIRENTRY) DirectoryBuffer;
for (CurrentEntry=0; CurrentEntry<EntryCount; CurrentEntry++, DirEntry++)
{
LfnDirEntry = (PLFN_DIRENTRY)DirEntry;
//DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry %d:\n", CurrentEntry));
//DbgDumpBuffer(DPRINT_FILESYSTEM, DirEntry, sizeof(DIRENTRY));
//
// Check if this is the last file in the directory
// If DirEntry[0] == 0x00 then that means all the
// entries after this one are unused. If this is the
// last entry then we didn't find the file in this directory.
//
if (DirEntry->FileName[0] == '\0')
{
return FALSE;
}
//
// Check if this is a deleted entry or not
//
if (DirEntry->FileName[0] == '\xE5')
{
memset(ShortNameBuffer, 0, 13 * sizeof(CHAR));
memset(LfnNameBuffer, 0, 261 * sizeof(CHAR));
continue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -