488 lines
10 KiB
C
488 lines
10 KiB
C
#include "lfn.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
PMYTEXTFILE
|
|
ReadRenameFile(
|
|
IN PCWSTR DriveRootPath
|
|
);
|
|
|
|
BOOLEAN
|
|
FindSections(
|
|
IN PMYTEXTFILE TextFile
|
|
);
|
|
|
|
BOOLEAN
|
|
GetLine(
|
|
IN PWCHAR StartOfLine,
|
|
OUT PWSTR LineBuffer,
|
|
IN ULONG BufferSizeChars,
|
|
OUT PWCHAR *StartOfNextLine
|
|
);
|
|
|
|
int
|
|
__cdecl
|
|
ComparePaths(
|
|
const void *p1,
|
|
const void *p2
|
|
);
|
|
|
|
|
|
PMYTEXTFILE
|
|
LoadRenameFile(
|
|
IN PCWSTR DriveRootPath
|
|
)
|
|
{
|
|
PMYTEXTFILE TextFile;
|
|
BOOLEAN b;
|
|
|
|
//
|
|
// Read in the file.
|
|
//
|
|
if(TextFile = ReadRenameFile(DriveRootPath)) {
|
|
|
|
if(b = FindSections(TextFile)) {
|
|
|
|
return(TextFile);
|
|
}
|
|
|
|
UnloadRenameFile(&TextFile);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
UnloadRenameFile(
|
|
IN OUT PMYTEXTFILE *TextFile
|
|
)
|
|
{
|
|
PMYTEXTFILE textFile;
|
|
ULONG u;
|
|
|
|
textFile = *TextFile;
|
|
*TextFile = NULL;
|
|
|
|
if(textFile->Sections) {
|
|
|
|
for(u=0; u<textFile->SectionCount; u++) {
|
|
FREE(textFile->Sections[u].Name);
|
|
}
|
|
|
|
FREE(textFile->Sections);
|
|
}
|
|
|
|
FREE(textFile);
|
|
}
|
|
|
|
|
|
PMYTEXTFILE
|
|
ReadRenameFile(
|
|
IN PCWSTR DriveRootPath
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WCHAR FullPath[NTMAXPATH] = {0};
|
|
HANDLE Handle;
|
|
FILE_STANDARD_INFORMATION FileInfo;
|
|
PVOID Buffer;
|
|
PWCHAR UnicodeBuffer;
|
|
ULONG u;
|
|
PMYTEXTFILE p = NULL;
|
|
ULONG CharCount;
|
|
|
|
wcsncpy(FullPath,DriveRootPath,sizeof(FullPath)/sizeof(FullPath[0]) - 1);
|
|
ConcatenatePaths(FullPath,WINNT_OEM_LFNLIST_W,NTMAXPATH);
|
|
|
|
//
|
|
// Open the file.
|
|
//
|
|
INIT_OBJA(&ObjectAttributes,&UnicodeString,FullPath);
|
|
Status = NtCreateFile(
|
|
&Handle,
|
|
FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_ALERT | FILE_NON_DIRECTORY_FILE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("LFN: Unable to open %ws (%x)\n",FullPath,Status));
|
|
goto c0;
|
|
}
|
|
|
|
//
|
|
// Determine the size of the file.
|
|
//
|
|
Status = NtQueryInformationFile(
|
|
Handle,
|
|
&IoStatusBlock,
|
|
&FileInfo,
|
|
sizeof(FileInfo),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("LFN: Unable to determine size of %ws (%x)\n",FullPath,Status));
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Allocate a chunk of memory and read the file in.
|
|
//
|
|
Buffer = MALLOC(FileInfo.EndOfFile.LowPart);
|
|
if(!Buffer) {
|
|
KdPrint(("LFN: malloc failed\n"));
|
|
goto c1;
|
|
}
|
|
|
|
Status = NtReadFile(
|
|
Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
Buffer,
|
|
FileInfo.EndOfFile.LowPart,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint((
|
|
"LFN: Unable to read %u bytes from file %ws (%x)\n",
|
|
FileInfo.EndOfFile.LowPart,
|
|
FullPath,
|
|
Status
|
|
));
|
|
goto c2;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for unicode conversion.
|
|
// Leave room for a terminating NUL.
|
|
//
|
|
UnicodeBuffer = MALLOC((FileInfo.EndOfFile.LowPart+1)*sizeof(WCHAR));
|
|
if(!UnicodeBuffer) {
|
|
KdPrint(("LFN: malloc failed\n"));
|
|
goto c2;
|
|
}
|
|
|
|
//
|
|
// Convert to unicode.
|
|
//
|
|
Status = RtlOemToUnicodeN(
|
|
UnicodeBuffer,
|
|
FileInfo.EndOfFile.LowPart*sizeof(WCHAR),
|
|
&CharCount,
|
|
Buffer,
|
|
FileInfo.EndOfFile.LowPart
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("LFN: Unable to convert file data to unicode (%x)\n",Status));
|
|
goto c3;
|
|
}
|
|
|
|
CharCount /= sizeof(WCHAR);
|
|
|
|
//
|
|
// Nul-terminate the buffer and change instances of CR and control-z
|
|
// to spaces. Also make sure there are no 0 chars in the buffer.
|
|
//
|
|
for(u=0; u<CharCount; u++) {
|
|
if((UnicodeBuffer[u] == 26) || (UnicodeBuffer[u] == L'\r') || !UnicodeBuffer[u]) {
|
|
UnicodeBuffer[u] = L' ';
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate a text file structure.
|
|
//
|
|
p = MALLOC(sizeof(MYTEXTFILE));
|
|
if(!p) {
|
|
KdPrint(("LFN: malloc failed\n"));
|
|
goto c3;
|
|
}
|
|
|
|
RtlZeroMemory(p,sizeof(MYTEXTFILE));
|
|
p->Text = UnicodeBuffer;
|
|
UnicodeBuffer[CharCount] = 0;
|
|
|
|
c3:
|
|
if(!NT_SUCCESS(Status)) {
|
|
FREE(UnicodeBuffer);
|
|
}
|
|
c2:
|
|
FREE(Buffer);
|
|
c1:
|
|
NtClose(Handle);
|
|
c0:
|
|
return(NT_SUCCESS(Status) ? p : NULL);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FindSections(
|
|
IN PMYTEXTFILE TextFile
|
|
)
|
|
{
|
|
PWCHAR p,n;
|
|
WCHAR Line[2*NTMAXPATH];
|
|
PWCHAR e;
|
|
PVOID NewArray;
|
|
PWCHAR s;
|
|
PWSTR SectionName;
|
|
|
|
for(p=TextFile->Text; GetLine(p,Line,sizeof(Line)/sizeof(WCHAR),&n); p=n) {
|
|
|
|
//
|
|
// If this is a section save it away in a table of section names.
|
|
//
|
|
if(Line[0] == L'[') {
|
|
|
|
s = Line+1;
|
|
while((*s == L' ') || (*s == L'\t')) {
|
|
s++;
|
|
}
|
|
if(*s == L'\\') {
|
|
s++;
|
|
}
|
|
|
|
//
|
|
// Find the end, which is either the ] or a nul.
|
|
// Strip off trailing spaces.
|
|
//
|
|
if(e = wcschr(s,L']')) {
|
|
*e = 0;
|
|
} else {
|
|
e = wcschr(s,0);
|
|
}
|
|
while((*(e-1) == L' ') || (*(e-1) == L'\t')) {
|
|
e--;
|
|
*e = 0;
|
|
}
|
|
|
|
if(SectionName = MALLOC((wcslen(s)+1)*sizeof(WCHAR))) {
|
|
|
|
wcscpy(SectionName,s);
|
|
|
|
if(TextFile->SectionCount == TextFile->SectionArraySize) {
|
|
|
|
if(TextFile->SectionCount) {
|
|
NewArray = REALLOC(TextFile->Sections,(TextFile->SectionCount+10)*sizeof(MYSECTION));
|
|
} else {
|
|
NewArray = MALLOC(10*sizeof(MYSECTION));
|
|
}
|
|
|
|
if(NewArray) {
|
|
TextFile->Sections = NewArray;
|
|
TextFile->SectionArraySize += 10;
|
|
} else {
|
|
FREE(SectionName);
|
|
KdPrint(("LFN: malloc failed\n"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
TextFile->Sections[TextFile->SectionCount].Name = SectionName;
|
|
TextFile->Sections[TextFile->SectionCount].Data = n;
|
|
|
|
TextFile->SectionCount++;
|
|
|
|
} else {
|
|
KdPrint(("LFN: malloc failed\n"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now sort the sections by name.
|
|
//
|
|
qsort(TextFile->Sections,TextFile->SectionCount,sizeof(MYSECTION),ComparePaths);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
GetLineInSection(
|
|
IN PWCHAR StartOfLine,
|
|
OUT PWSTR LineBuffer,
|
|
IN ULONG BufferSizeChars,
|
|
OUT PWCHAR *StartOfNextLine
|
|
)
|
|
{
|
|
//
|
|
// Get the line and check if we've reached the end of the section.
|
|
//
|
|
if(!GetLine(StartOfLine,LineBuffer,BufferSizeChars,StartOfNextLine)
|
|
|| (LineBuffer[0] == L'[')) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
GetLine(
|
|
IN PWCHAR StartOfLine,
|
|
OUT PWSTR LineBuffer,
|
|
IN ULONG BufferSizeChars,
|
|
OUT PWCHAR *StartOfNextLine
|
|
)
|
|
{
|
|
PWCHAR LineEnd;
|
|
SIZE_T Count;
|
|
|
|
while(1) {
|
|
//
|
|
// Skip space chars.
|
|
//
|
|
while(*StartOfLine && ((*StartOfLine == L' ') || (*StartOfLine == L'\t'))) {
|
|
StartOfLine++;
|
|
}
|
|
if(*StartOfLine == 0) {
|
|
//
|
|
// Nothing left.
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find the end of the line, which is either the newline or nul.
|
|
//
|
|
if(LineEnd = wcschr(StartOfLine,L'\n')) {
|
|
*StartOfNextLine = LineEnd+1;
|
|
} else {
|
|
LineEnd = wcschr(StartOfLine,0);
|
|
*StartOfNextLine = LineEnd;
|
|
}
|
|
|
|
//
|
|
// Ignore this line if it's a comment or empty.
|
|
// Otherwise return it.
|
|
//
|
|
if((*StartOfLine != L';') && (*StartOfLine != L' ')) {
|
|
Count = LineEnd - StartOfLine;
|
|
if(Count >= BufferSizeChars) {
|
|
Count = BufferSizeChars-1;
|
|
}
|
|
|
|
RtlCopyMemory(LineBuffer,StartOfLine,Count*sizeof(WCHAR));
|
|
LineBuffer[Count] = 0;
|
|
return(TRUE);
|
|
}
|
|
|
|
StartOfLine = *StartOfNextLine;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
__cdecl
|
|
ComparePaths(
|
|
const void *p1,
|
|
const void *p2
|
|
)
|
|
{
|
|
unsigned u1,u2;
|
|
PWCHAR s1,s2;
|
|
|
|
//
|
|
// Count \'s in each. The one with fewer is 'greater'.
|
|
//
|
|
s1 = ((PMYSECTION)p1)->Name;
|
|
s2 = ((PMYSECTION)p2)->Name;
|
|
|
|
u1 = 0;
|
|
u2 = 0;
|
|
|
|
while(*s1) {
|
|
if(*s1 == L'\\') {
|
|
u1++;
|
|
}
|
|
s1++;
|
|
}
|
|
|
|
while(*s2) {
|
|
if(*s2 == L'\\') {
|
|
u2++;
|
|
}
|
|
s2++;
|
|
}
|
|
|
|
if(u1 == u2) {
|
|
return(0);
|
|
}
|
|
|
|
return((u1 < u2) ? 1 : -1);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ParseLine(
|
|
IN OUT PWSTR Line,
|
|
OUT PWSTR *LHS,
|
|
OUT PWSTR *RHS
|
|
)
|
|
{
|
|
PWCHAR p,q;
|
|
|
|
//
|
|
// We rely on the routines abive to have stripped out
|
|
// leading spaces.
|
|
//
|
|
*LHS = Line;
|
|
|
|
//
|
|
// Find the equals. The LHS isn't allowed to be quoted.
|
|
// Strip trailing space off the LHS.
|
|
//
|
|
p = wcschr(Line,L'=');
|
|
if(!p || (p == Line)) {
|
|
return(FALSE);
|
|
}
|
|
q = p+1;
|
|
*p-- = 0;
|
|
|
|
while((*p == L' ') || (*p == L'\t')) {
|
|
*p-- = 0;
|
|
}
|
|
|
|
while(*q && ((*q == L' ') || (*q == L'\t'))) {
|
|
q++;
|
|
}
|
|
if(*q == 0) {
|
|
return(FALSE);
|
|
}
|
|
if(*q == L'\"') {
|
|
q++;
|
|
}
|
|
|
|
*RHS = q;
|
|
p = q + wcslen(q);
|
|
p--;
|
|
while((*p == L' ') || (*p == L'\t')) {
|
|
*p-- = 0;
|
|
}
|
|
if(*p == L'\"') {
|
|
*p = 0;
|
|
}
|
|
return(TRUE);
|
|
}
|