/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: infflist.c Abstract: Externally exposed routines for manipulating file lists, disk descriptors, and directory descriptors in INF files. Author: Ted Miller (tedm) 3-Feb-1995 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include // // Locations of various fields on lines in a copy section. // First field is 'target' filename. // Second field is 'source' filename and is optional for copy sections // and not used at all in delete sections. #define COPYSECT_TARGET_FILENAME 1 #define COPYSECT_SOURCE_FILENAME 2 // // Locations of various fields on lines in a file layout section. // #define LAYOUTSECT_FILENAME 0 // key #define LAYOUTSECT_DISKID 1 #define LAYOUTSECT_SUBDIR 2 #define LAYOUTSECT_SIZE 3 #define LAYOUTSECT_CHECKSUM 4 // // Locations of various fields on lines in a [DestinationDirs] section. // #define DIRSECT_DIRID 1 #define DIRSECT_SUBDIR 2 // // Names of various sections in an INF. // (string constants defined in infstr.h) // CONST TCHAR pszSourceDisksNames[] = SZ_KEY_SRCDISKNAMES, pszSourceDisksFiles[] = SZ_KEY_SRCDISKFILES, pszDestinationDirs[] = SZ_KEY_DESTDIRS, pszDefaultDestDir[] = SZ_KEY_DEFDESTDIR; BOOL _SetupGetSourceFileLocation( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR FileName, OPTIONAL IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL OUT PUINT SourceId, OPTIONAL OUT PTSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize, OPTIONAL OUT PINFCONTEXT LineContext OPTIONAL ) /*++ Routine Description: Determine the location of a source file, as listed in an inf file. Arguments: InfHandle - supplies the handle to a loaded inf file that contains file layout information, ie, has [SourceDisksNames] and [SourceDisksFiles] sections. InfContext - specifies a line in a copy section of an inf file for which the full source path is to be retreived. If this parameter is not specified, then FileName will be searched for in the [SourceDisksFiles] section of the INF specified by InfHandle. FileName - supplies the filename (no path) for which to return the full source location. Must be specified if InfContext is not. AltPlatformInfo - optionally, supplies alternate platform to be used when looking for decorated [SourceDisksFiles] section. SourceId - receives the source id of the source media where the file is located. This parameter may be NULL if this information is not desired. ReturnBuffer - receives the source path (relative to the source LDD). This path contains neither a drivespec nor the filename itself. The path never starts or ends with \, so the empty string means the root. ReturnBufferSize - specified the size in characters of the buffer pointed to by ReturnBuffer. RequiredSize - receives the number of characters required in ReturnBuffer. If the buffer is too small GetLastError returns ERROR_INSUFFICIENT_BUFFER. Return Value: Boolean value indicating outcome. --*/ { PCTSTR fileName, PlatformName; INFCONTEXT DecContext; INFCONTEXT UnDecContext; PINFCONTEXT lineContext; UINT Length; PCTSTR SubDir; TCHAR FileListSectionName[64]; BOOL bDec = FALSE; BOOL bUnDec = FALSE; // // If caller gave a line context, the first field on the line // is the filename. Retreive it. // try { fileName = InfContext ? pSetupGetField(InfContext,COPYSECT_TARGET_FILENAME) : FileName; } except(EXCEPTION_EXECUTE_HANDLER) { // // InfContext must be a bad pointer // fileName = NULL; } if(!fileName) { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } // // Now look for the filename's line in the [SourceDisksFiles] section. // Look in the platform-specific one first and the platform-independent // one if not found. // if(AltPlatformInfo) { switch(AltPlatformInfo->ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : PlatformName = pszX86SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_ALPHA : PlatformName = pszAlphaSrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_IA64 : PlatformName = pszIa64SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_ALPHA64 : PlatformName = pszAxp64SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_AMD64 : PlatformName = pszAmd64SrcDiskSuffix; break; default : // // unknown/unsupported processor architecture. // MYASSERT((AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA64) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ); SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } } else { PlatformName = pszPlatformSrcDiskSuffix; } _sntprintf(FileListSectionName, SIZECHARS(FileListSectionName), TEXT("%s.%s"), pszSourceDisksFiles, PlatformName ); bDec = SetupFindFirstLine(InfHandle,FileListSectionName,fileName,&DecContext); if(bDec && (DecContext.CurrentInf == InfHandle)) { // // found Decorated section in same INF as source file // lineContext = &DecContext; } else { // // didn't find decorated section in expected INF, try undecorated in expected INF // bUnDec = SetupFindFirstLine(InfHandle,pszSourceDisksFiles,fileName,&UnDecContext); if(bUnDec && (UnDecContext.CurrentInf == InfHandle)) { // // found in Undecorated section in same INF as source file // lineContext = &UnDecContext; } else if(bDec) { // // any decorated section (should only be one) // lineContext = &DecContext; } else if(bUnDec) { // // any undecorated section (should only be one) // lineContext = &UnDecContext; } else { // // none found // SetLastError(ERROR_LINE_NOT_FOUND); return(FALSE); } } // // Got the line. If the caller wants it, give it to him. // We don't guard this with try/except because this routine is internal // and any fault is a bug in the caller. // if(LineContext) { *LineContext = *lineContext; } // // Get the disk id. // if(SourceId) { if(!SetupGetIntField(lineContext,LAYOUTSECT_DISKID,SourceId)) { SetLastError(ERROR_INVALID_DATA); return(FALSE); } } // // If all the caller was interested in was the disk ID (i.e., they passed in ReturnBuffer // and RequiredSize both as NULL), then we can save the extra work and return now. // if(!(ReturnBuffer || RequiredSize)) { return TRUE; } // // Now get the path relative to the LDD. // SubDir = pSetupGetField(lineContext,LAYOUTSECT_SUBDIR); if(!SubDir) { SubDir = TEXT(""); } Length = lstrlen(SubDir); // // Ignore leading path sep if present. // if(SubDir[0] == TEXT('\\')) { Length--; SubDir++; } // // See if there's a trailing path sep. // if(Length && *CharPrev(SubDir,SubDir+Length) == TEXT('\\')) { Length--; } // // Leave space for the nul // if(RequiredSize) { *RequiredSize = Length+1; } // // Place data in caller's buffer. // If caller didn't specify a buffer we're done. // if(ReturnBuffer) { if(ReturnBufferSize <= Length) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return(FALSE); } // // Don't use lstrcpy, because if we are stripping // a trailing path sep, lstrcpy could write the nul byte // past the end of the buffer. // CopyMemory(ReturnBuffer,SubDir,Length*sizeof(TCHAR)); ReturnBuffer[Length] = 0; } return(TRUE); } #ifdef UNICODE // // ANSI version // BOOL SetupGetSourceFileLocationA( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCSTR FileName, OPTIONAL OUT PUINT SourceId, OUT PSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { WCHAR returnbuffer[MAX_PATH]; DWORD requiredsize; PCWSTR filename; UINT sourceid; DWORD rc; BOOL b; PCSTR ansireturn; rc = NO_ERROR; if(FileName) { rc = pSetupCaptureAndConvertAnsiArg(FileName,&filename); if(rc != NO_ERROR) { SetLastError(rc); return(FALSE); } } else { filename = NULL; } b = _SetupGetSourceFileLocation( InfHandle, InfContext, filename, NULL, &sourceid, returnbuffer, MAX_PATH, &requiredsize, NULL ); rc = GetLastError(); if(b) { rc = NO_ERROR; if(ansireturn = pSetupUnicodeToAnsi(returnbuffer)) { requiredsize = lstrlenA(ansireturn)+1; try { *SourceId = sourceid; if(RequiredSize) { *RequiredSize = requiredsize; } } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } if(rc == NO_ERROR) { if(ReturnBuffer) { if(requiredsize <= ReturnBufferSize) { // // lstrcpy won't generate an exception on NT even if // ReturnBuffer is invalid, but will return NULL // try { if(!lstrcpyA(ReturnBuffer,ansireturn)) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } except(EXCEPTION_EXECUTE_HANDLER) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } else { b = FALSE; rc = ERROR_INSUFFICIENT_BUFFER; } } } MyFree(ansireturn); } else { b = FALSE; rc = ERROR_NOT_ENOUGH_MEMORY; } } if(filename) { MyFree(filename); } SetLastError(rc); return(b); } #else // // Unicode stub // BOOL SetupGetSourceFileLocationW( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCWSTR FileName, OPTIONAL OUT PUINT SourceId, OUT PWSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { UNREFERENCED_PARAMETER(InfHandle); UNREFERENCED_PARAMETER(InfContext); UNREFERENCED_PARAMETER(FileName); UNREFERENCED_PARAMETER(SourceId); UNREFERENCED_PARAMETER(ReturnBuffer); UNREFERENCED_PARAMETER(ReturnBufferSize); UNREFERENCED_PARAMETER(RequiredSize); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return(FALSE); } #endif BOOL SetupGetSourceFileLocation( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR FileName, OPTIONAL OUT PUINT SourceId, OUT PTSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { TCHAR returnbuffer[MAX_PATH]; DWORD requiredsize; PCTSTR filename; UINT sourceid; DWORD rc; BOOL b; rc = NO_ERROR; if(FileName) { rc = CaptureStringArg(FileName,&filename); if(rc != NO_ERROR) { SetLastError(rc); return(FALSE); } } else { filename = NULL; } b = _SetupGetSourceFileLocation( InfHandle, InfContext, filename, NULL, &sourceid, returnbuffer, MAX_PATH, &requiredsize, NULL ); rc = GetLastError(); if(b) { rc = NO_ERROR; try { *SourceId = sourceid; if(RequiredSize) { *RequiredSize = requiredsize; } } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } if(rc == NO_ERROR) { if(ReturnBuffer) { if(requiredsize <= ReturnBufferSize) { // // lstrcpy won't generate an exception on NT even if // ReturnBuffer is invalid, but will return NULL // try { if(!lstrcpy(ReturnBuffer,returnbuffer)) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } except(EXCEPTION_EXECUTE_HANDLER) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } else { b = FALSE; rc = ERROR_INSUFFICIENT_BUFFER; } } } } if(filename) { MyFree(filename); } SetLastError(rc); return(b); } BOOL _SetupGetSourceFileSize( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR FileName, OPTIONAL IN PCTSTR Section, OPTIONAL IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL OUT PDWORD FileSize, IN UINT RoundingFactor OPTIONAL ) /*++ Routine Description: Determine the (uncompressed) size of a source file, as listed in an inf file. Arguments: InfHandle - supplies the handle to a loaded inf file that contains file layout information, ie, has [SourceDisksNames] and optionally [SourceDisksFiles] sections. InfContext - specifies a line in a the copy section of an inf file for which the size is to be retreived. If this parameter is not specified, the FileName parameter is checked next. FileName - supplies the filename (no path) for which to return the size. If this parameter is not specified the Section parameter is used (see below). Section - specifies the name of a section in the INF file specified by InfHandle. The total sizes of all files in the section is computed. AltPlatformInfo - optionally, supplies alternate platform information to be used in selecting a decorated [SourceDisksFiles] section. FileSize - receives the file size(s). RoundingFactor - If specified, supplies a value for rounding file sizes. All file sizes will be rounded up to be a multiple of this number before being added to the total size. This is useful for more exact determinations of the space a file will occupy on a given volume, because it allows the caller to have file sizes rounded up to be a multiple of the cluster size. If not specified no rounding takes place. Return Value: Boolean value indicating outcome. --*/ { PCTSTR fileName, PlatformName; INFCONTEXT LayoutSectionContext; INFCONTEXT CopySectionContext; BOOL b; UINT Size; LONG File,FileCount; TCHAR FileListSectionName[64]; DWORD rc; // // If the rounding factor is not specified, set it to 1 so the math // below works without special cases. // if(!RoundingFactor) { RoundingFactor = 1; } // Establish an inf line context for the line in the copy list section, // unless the caller passed us an absolute filename. // fileName = NULL; FileCount = 1; if(InfContext) { // // Caller passed INF line context. // Remember the context in preparation for retreiving the filename // from the line later. // // fileName must be NULL so we look at the line // and get the correct source name // b = TRUE; try { CopySectionContext = *InfContext; } except(EXCEPTION_EXECUTE_HANDLER) { b = FALSE; } if(!b) { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } } else { if(FileName) { // // Caller passed an absolute file name. Remember it. // fileName = FileName; } else { // // Caller must have passed a section, the contents of which lists // a set of files whose sizes are to be totalled. Determine the number // of lines in the section and establish a context. // if(Section) { FileCount = SetupGetLineCount(InfHandle,Section); if((FileCount == -1) || !SetupFindFirstLine(InfHandle,Section,NULL,&CopySectionContext)) { rc = GetLastError(); pSetupLogSectionError(InfHandle,NULL,NULL,NULL,Section,MSG_LOG_NOSECTION_FILESIZE,rc,NULL); SetLastError(ERROR_SECTION_NOT_FOUND); // ignoring rc for compatability with older versions of setupAPI return(FALSE); } } else { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } } } *FileSize = 0; for(File=0; FileProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL : PlatformName = pszX86SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_ALPHA : PlatformName = pszAlphaSrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_IA64 : PlatformName = pszIa64SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_ALPHA64 : PlatformName = pszAxp64SrcDiskSuffix; break; case PROCESSOR_ARCHITECTURE_AMD64 : PlatformName = pszAmd64SrcDiskSuffix; break; default : // // unknown/unsupported processor architecture. // MYASSERT((AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA64) || (AltPlatformInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ); SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } } else { PlatformName = pszPlatformSrcDiskSuffix; } _sntprintf( FileListSectionName, sizeof(FileListSectionName)/sizeof(FileListSectionName[0]), TEXT("%s.%s"), pszSourceDisksFiles, PlatformName ); b = SetupFindFirstLine(InfHandle,FileListSectionName,fileName,&LayoutSectionContext); if(!b) { b = SetupFindFirstLine(InfHandle,pszSourceDisksFiles,fileName,&LayoutSectionContext); } if(!b) { SetLastError(ERROR_LINE_NOT_FOUND); return(FALSE); } // // Get the size data for the file. // b = SetupGetIntField(&LayoutSectionContext,LAYOUTSECT_SIZE,&Size); if(!b) { SetLastError(ERROR_INVALID_DATA); return(FALSE); } // // Round size up to be an even multiple of the rounding factor // if(Size % RoundingFactor) { Size += RoundingFactor - (Size % RoundingFactor); } *FileSize += Size; } return(TRUE); } #ifdef UNICODE // // ANSI version // BOOL SetupGetSourceFileSizeA( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCSTR FileName, OPTIONAL IN PCSTR Section, OPTIONAL OUT PDWORD FileSize, IN UINT RoundingFactor OPTIONAL ) { PCWSTR filename,section; BOOL b; DWORD rc; DWORD size; if(FileName) { rc = pSetupCaptureAndConvertAnsiArg(FileName,&filename); if(rc != NO_ERROR) { SetLastError(rc); return(FALSE); } } else { filename = NULL; } if(Section) { rc = pSetupCaptureAndConvertAnsiArg(Section,§ion); if(rc != NO_ERROR) { if(filename) { MyFree(filename); } SetLastError(rc); return(FALSE); } } else { section = NULL; } b = _SetupGetSourceFileSize(InfHandle, InfContext, filename, section, NULL, &size, RoundingFactor ); rc = GetLastError(); if (b) { try { *FileSize = size; } except(EXCEPTION_EXECUTE_HANDLER) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } if(filename) { MyFree(filename); } if(section) { MyFree(section); } SetLastError(rc); return(b); } #else // // Unicode stub // BOOL SetupGetSourceFileSizeW( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCWSTR FileName, OPTIONAL IN PCWSTR Section, OPTIONAL OUT PDWORD FileSize, IN UINT RoundingFactor OPTIONAL ) { UNREFERENCED_PARAMETER(InfHandle); UNREFERENCED_PARAMETER(InfContext); UNREFERENCED_PARAMETER(FileName); UNREFERENCED_PARAMETER(Section); UNREFERENCED_PARAMETER(FileSize); UNREFERENCED_PARAMETER(RoundingFactor); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return(FALSE); } #endif BOOL SetupGetSourceFileSize( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR FileName, OPTIONAL IN PCTSTR Section, OPTIONAL OUT PDWORD FileSize, IN UINT RoundingFactor OPTIONAL ) { PCTSTR filename,section; BOOL b; DWORD rc; DWORD size; if(FileName) { rc = CaptureStringArg(FileName,&filename); if(rc != NO_ERROR) { SetLastError(rc); return(FALSE); } } else { filename = NULL; } if(Section) { rc = CaptureStringArg(Section,§ion); if(rc != NO_ERROR) { if(filename) { MyFree(filename); } SetLastError(rc); return(FALSE); } } else { section = NULL; } b = _SetupGetSourceFileSize(InfHandle, InfContext, filename, section, NULL, &size, RoundingFactor ); rc = GetLastError(); if (b) { try { *FileSize = size; } except(EXCEPTION_EXECUTE_HANDLER) { b = FALSE; rc = ERROR_INVALID_PARAMETER; } } if(filename) { MyFree(filename); } if(section) { MyFree(section); } SetLastError(rc); return(b); } BOOL _SetupGetTargetPath( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR Section, OPTIONAL OUT PTSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) /*++ Routine Description: Determine the target directory for a given file list section. A file list section may be for copy, rename, or delete; in any case all the files in the section are in one directory and that directory is listed in the [DestinationDirs] section of the inf. Where InfContext is specified, we will look for [DestinationDirs] from the current inf in the context first. This will help the scenario where X.INF includes Y.INF includes LAYOUT.INF, both X&Y have entries but the section was found in Y. We want to find the section in X last. Arguments: InfHandle - supplies the handle to a loaded inf file that contains a [DestinationDirs] section. InfContext - specifies a line in a the copy section of an inf file. The target directory for this section is retreived. Section - Supplies the section in InfHandle whose destination directory is to be retreived. Ignored if InfContext is specified. If neither InfContext nor Section are specified, this function retreives the default target path. ReturnBuffer - if specified, receives the full win32 path of the target. This value is guaranteed not to end with \. ReturnBufferSize - specifies the size in characters of the buffer pointed to by ReturnBuffer. RequiredSize - receives the size in characters of a buffer required to hold the output data. Return Value: Boolean value indicating outcome. GetLastError() returns extended error info. ERROR_INSUFFICIENT_BUFFER is returned if the function fails because ReturnBuffer is too small. --*/ { PINF_SECTION DestDirsSection; UINT LineNumber; PINF_LINE Line; PCTSTR DirId; PCTSTR SubDir; PCTSTR ActualPath; UINT DirIdInt; PLOADED_INF Inf, CurInf, DefaultDestDirInf; DWORD TmpRequiredSize; BOOL DestDirFound, DefaultDestDirFound; DWORD Err; PINF_LINE DefaultDestDirLine; PCTSTR InfSourcePath; // // If an INF context was specified, use it to determine the name // the section the context describes. If inf context was not specified, // then a section name must have been. // Err = NO_ERROR; try { Inf = InfContext ? (PLOADED_INF)InfContext->Inf : (PLOADED_INF)InfHandle; if(!LockInf(Inf)) { Err = ERROR_INVALID_HANDLE; } } except(EXCEPTION_EXECUTE_HANDLER) { Err = ERROR_INVALID_PARAMETER; } if(Err != NO_ERROR) { SetLastError(Err); return(FALSE); } // // If we get here then InfContext is a good pointer if specified; // if not then Inf is a good pointer. // if(InfContext) { CurInf = (PLOADED_INF)InfContext->CurrentInf; InfSourcePath = CurInf->InfSourcePath; Section = pStringTableStringFromId( CurInf->StringTable, CurInf->SectionBlock[InfContext->Section].SectionName ); } else { InfSourcePath = Inf->InfSourcePath; if(!Section) { Section = pszDefaultDestDir; } } // // Traverse the linked list of INFs, looking for a [DestinationDirs] section // in each one. // DestDirFound = DefaultDestDirFound = FALSE; Err = NO_ERROR; if (InfContext) { // // first consider the CurrentInf as being Local scope // CurInf = InfContext->CurrentInf; if((DestDirsSection = InfLocateSection(CurInf, pszDestinationDirs, NULL))!=NULL) { // // Locate the line in [DestinationDirs] that gives the target path // for the section. The section name will be the key on the relevant line. // If that's not there, and we haven't already encountered a DefaultDestDir // entry, then look for that as well, and remember it if we find one. // LineNumber = 0; if(InfLocateLine(CurInf, DestDirsSection, Section, &LineNumber, &Line)) { // // Got the line in [DestinationDirs]. Pull out the directory. The subdir is optional. // DirId = InfGetField(CurInf, Line, DIRSECT_DIRID, NULL); if(!DirId) { Err = ERROR_INVALID_DATA; goto clean0; } SubDir = InfGetField(CurInf, Line, DIRSECT_SUBDIR, NULL); DestDirFound = TRUE; } else if(InfLocateLine(CurInf, DestDirsSection, pszDefaultDestDir, &LineNumber, &Line)) { DefaultDestDirInf = CurInf; DefaultDestDirLine = Line; DefaultDestDirFound = TRUE; } } } if(!DestDirFound && !DefaultDestDirFound) { // // search for any matches at all // for(CurInf = Inf; CurInf; CurInf = CurInf->Next) { if(!(DestDirsSection = InfLocateSection(CurInf, pszDestinationDirs, NULL))) { continue; } // // Locate the line in [DestinationDirs] that gives the target path // for the section. The section name will be the key on the relevant line. // If that's not there, and we haven't already encountered a DefaultDestDir // entry, then look for that as well, and remember it if we find one. // LineNumber = 0; if(InfLocateLine(CurInf, DestDirsSection, Section, &LineNumber, &Line)) { // // Got the line in [DestinationDirs]. Pull out the directory. The subdir is optional. // DirId = InfGetField(CurInf, Line, DIRSECT_DIRID, NULL); if(!DirId) { Err = ERROR_INVALID_DATA; goto clean0; } SubDir = InfGetField(CurInf, Line, DIRSECT_SUBDIR, NULL); DestDirFound = TRUE; break; } if(!DefaultDestDirFound && InfLocateLine(CurInf, DestDirsSection, pszDefaultDestDir, &LineNumber, &Line)) { DefaultDestDirInf = CurInf; DefaultDestDirLine = Line; DefaultDestDirFound = TRUE; } } } if(!DestDirFound) { // // If we found a DefaultDestDir, then use that, otherwise, use a default. // if(DefaultDestDirFound) { DirId = InfGetField(DefaultDestDirInf, DefaultDestDirLine, DIRSECT_DIRID, NULL); if(!DirId) { Err = ERROR_INVALID_DATA; goto clean0; } SubDir = InfGetField(DefaultDestDirInf, DefaultDestDirLine, DIRSECT_SUBDIR, NULL); CurInf = DefaultDestDirInf; } else { SubDir = NULL; DirId = NULL; DirIdInt = DIRID_DEFAULT; CurInf = NULL; } } // // Translate dirid/subdir to actual path. // ActualPath = pSetupDirectoryIdToPath(DirId, &DirIdInt, SubDir, InfSourcePath, (CurInf && CurInf->OsLoaderPath) ? &(CurInf->OsLoaderPath) : NULL ); if(!ActualPath) { // // If the default DIRID lookup failed because DirId is in the // user-defined range, then GetLastError will return NO_ERROR. // Otherwise, we should bail now. // if((Err = GetLastError()) != NO_ERROR) { goto clean0; } // // Now see if we there's a user-defined DIRID for this. // if(!(ActualPath = pSetupVolatileDirIdToPath(NULL, DirIdInt, SubDir, Inf))) { Err = GetLastError(); goto clean0; } } // // Put actual path in caller's buffer. // TmpRequiredSize = lstrlen(ActualPath) + 1; if(RequiredSize) { *RequiredSize = TmpRequiredSize; } if(ReturnBuffer) { if(TmpRequiredSize > ReturnBufferSize) { Err = ERROR_INSUFFICIENT_BUFFER; } else { lstrcpy(ReturnBuffer, ActualPath); } } MyFree(ActualPath); clean0: UnlockInf(Inf); if(Err == NO_ERROR) { return TRUE; } else { SetLastError(Err); return FALSE; } } #ifdef UNICODE // // ANSI version // BOOL SetupGetTargetPathA( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCSTR Section, OPTIONAL OUT PSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { BOOL b; DWORD rc; WCHAR returnbuffer[MAX_PATH]; DWORD requiredsize; PCWSTR section; PCSTR ansireturn; if(Section) { rc = pSetupCaptureAndConvertAnsiArg(Section,§ion); } else { section = NULL; rc = NO_ERROR; } if(rc == NO_ERROR) { b = _SetupGetTargetPath(InfHandle,InfContext,section,returnbuffer,MAX_PATH,&requiredsize); rc = GetLastError(); } else { b = FALSE; } if(b) { if(ansireturn = pSetupUnicodeToAnsi(returnbuffer)) { rc = NO_ERROR; requiredsize = lstrlenA(ansireturn) + 1; if(RequiredSize) { try { *RequiredSize = requiredsize; } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } } if(rc == NO_ERROR) { if(ReturnBuffer) { if(requiredsize <= ReturnBufferSize) { // // At least on NT lstrcpy won't fault if an arg is invalid // but it will return false. // if(!lstrcpyA(ReturnBuffer,ansireturn)) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } } else { rc = ERROR_INSUFFICIENT_BUFFER; b = FALSE; } } } MyFree(ansireturn); } else { b = FALSE; rc = ERROR_NOT_ENOUGH_MEMORY; } } if(section) { MyFree(section); } SetLastError(rc); return(b); } #else // // Unicode stub // BOOL SetupGetTargetPathW( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCWSTR Section, OPTIONAL OUT PWSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { UNREFERENCED_PARAMETER(InfHandle); UNREFERENCED_PARAMETER(InfContext); UNREFERENCED_PARAMETER(Section); UNREFERENCED_PARAMETER(ReturnBuffer); UNREFERENCED_PARAMETER(ReturnBufferSize); UNREFERENCED_PARAMETER(RequiredSize); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return(FALSE); } #endif BOOL SetupGetTargetPath( IN HINF InfHandle, IN PINFCONTEXT InfContext, OPTIONAL IN PCTSTR Section, OPTIONAL OUT PTSTR ReturnBuffer, OPTIONAL IN DWORD ReturnBufferSize, OUT PDWORD RequiredSize OPTIONAL ) { BOOL b; DWORD rc; TCHAR returnbuffer[MAX_PATH]; DWORD requiredsize; PCTSTR section; if(Section) { rc = CaptureStringArg(Section,§ion); } else { section = NULL; rc = NO_ERROR; } if(rc == NO_ERROR) { b = _SetupGetTargetPath(InfHandle,InfContext,section,returnbuffer,MAX_PATH,&requiredsize); rc = GetLastError(); } else { b = FALSE; } if(b) { rc = NO_ERROR; if(RequiredSize) { try { *RequiredSize = requiredsize; } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } } if(rc == NO_ERROR) { if(ReturnBuffer) { if(requiredsize <= ReturnBufferSize) { // // At least on NT lstrcpy won't fault if an arg is invalid // but it will return false. // if(!lstrcpy(ReturnBuffer,returnbuffer)) { rc = ERROR_INVALID_PARAMETER; b = FALSE; } } else { rc = ERROR_INSUFFICIENT_BUFFER; b = FALSE; } } } } if(section) { MyFree(section); } SetLastError(rc); return(b); } PCTSTR pSetupDirectoryIdToPath( IN PCTSTR DirectoryId, OPTIONAL IN OUT PUINT DirectoryIdInt, OPTIONAL IN PCTSTR SubDirectory, OPTIONAL IN PCTSTR InfSourcePath, OPTIONAL IN OUT PCTSTR *OsLoaderPath OPTIONAL ) /*++ (See pSetupDirectoryIdToPathEx for details.) --*/ { return pSetupDirectoryIdToPathEx(DirectoryId, DirectoryIdInt, SubDirectory, InfSourcePath, OsLoaderPath, NULL ); } PCTSTR pSetupDirectoryIdToPathEx( IN PCTSTR DirectoryId, OPTIONAL IN OUT PUINT DirectoryIdInt, OPTIONAL IN PCTSTR SubDirectory, OPTIONAL IN PCTSTR InfSourcePath, OPTIONAL IN OUT PCTSTR *OsLoaderPath, OPTIONAL OUT PBOOL VolatileSystemDirId OPTIONAL ) /*++ Routine Description: Translate a directory id/subdirectory pair to an actual path. The directory ids are reserved string values that we share with Win9x (and then some). VOLATILE SYSTEM DIRID PATHS AND USER-DEFINED DIRID PATHS ARE NOT RETURNED BY THIS ROUTINE!!! Arguments: DirectoryId - Optionally, supplies the (base-10) textual representation of the directory ID number to use. If this parameter is not specified, then DirectoryIdInt must be specified. DirectoryIdInt - Optionally, supplies the address of an integer variable that specifies, on input, the DIRID to use. This is only used if DirectoryID is not specified. On output, if DirectoryId was used, then this variable receives the numeric value contained in the DirectoryId string. SubDirectory - Optionally, supplies a subdirectory string that will be appended with the DIRID path. InfSourcePath - Optionally, supplies the path to be used if the ID turns out to be DIRID_SRCPATH. If this parameter is NULL, and the SourcePath DIRID is the one we are to use, then we use the global source path. OsLoaderPath - Optionally, supplies the address of a string pointer containing the OsLoader path. If the address points to a NULL string pointer, it will be filled in with a newly-allocated character buffer containing the OsLoader path, as retrieved from the registry. This will only be done if the DirectoryId being used is on the system partition. VolatileSystemDirId - Optionally, supplies the address of a boolean variable that, upon successful return, indicates whether or not the specified DIRID was a volatile system DIRID. Return Value: If successful, the return value is a pointer to a newly-allocated buffer containing the directory path matching the specified DIRID. THE CALLER IS RESPONSIBLE FOR FREEING THIS BUFFER! If failure, the return value is NULL. GetLastError() returns the reason for failure. If the failure was because the DIRID was a user-defined one, then GetLastError() will return NO_ERROR. --*/ { UINT Value; PTCHAR End; PCTSTR FirstPart; PTSTR Path; UINT Length; TCHAR Buffer[MAX_PATH]; BOOL b; DWORD err; if(VolatileSystemDirId) { *VolatileSystemDirId = FALSE; } if(DirectoryId) { // // We only allow base-10 integer ids for now. // Only the terminating nul should cause the conversion to stop. // In any other case there were non-digits in the string. // Also disallow the empty string. // Value = _tcstoul(DirectoryId, &End, 10); if(*End || (End == DirectoryId)) { SetLastError(ERROR_INVALID_DATA); return(NULL); } if(DirectoryIdInt) { *DirectoryIdInt = Value; } } else { MYASSERT(DirectoryIdInt); Value = *DirectoryIdInt; } if(!SubDirectory) { SubDirectory = TEXT(""); } Path = NULL; switch(Value) { case DIRID_NULL: case DIRID_ABSOLUTE: case DIRID_ABSOLUTE_16BIT: // // Absolute. // FirstPart = NULL; break; case DIRID_SRCPATH: // // If the caller supplied a path, then use it, otherwise, use our global default one. // if(InfSourcePath) { FirstPart = InfSourcePath; } else { FirstPart = SystemSourcePath; } break; case DIRID_BOOT: case DIRID_LOADER: // // System partition DIRIDS // if(OsLoaderPath && *OsLoaderPath) { lstrcpyn(Buffer, *OsLoaderPath, SIZECHARS(Buffer)); } else { err = pSetupGetOsLoaderDriveAndPath(FALSE, Buffer, SIZECHARS(Buffer), &Length); if(err) { SetLastError(err); return NULL; } if(OsLoaderPath) { // // allocate a buffer to return the OsLoaderPath to the caller. // Length *= sizeof(TCHAR); // need # bytes--not chars if(!(*OsLoaderPath = MyMalloc(Length))) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } CopyMemory((PVOID)(*OsLoaderPath), Buffer, Length); } } if(Value == DIRID_BOOT) { if(Buffer[0] && Buffer[1] == TEXT(':') && Buffer[2] == TEXT('\\')) { // // got a simple directory to return // Buffer[3] = TEXT('\0'); // just want ":\" part. } else { // // use OsSystemPartitionRoot instead // lstrcpyn(Buffer,OsSystemPartitionRoot,MAX_PATH); } } FirstPart = Buffer; break; case DIRID_SHARED: // // On Win95 there is an installation mode that allows most of // the OS to exist on a server. If the system is installed in that mode // DIRID_SHARED is the location of the windows dir on the server. // Otherwise it just maps to the windows dir. For now just map to // sysroot. // case DIRID_WINDOWS: // // Windows directory // FirstPart = WindowsDirectory; break; case DIRID_SYSTEM: // // Windows system directory // FirstPart = SystemDirectory; break; case DIRID_DRIVERS: // // io subsys directory (drivers) // FirstPart = DriversDirectory; break; case DIRID_INF: // // inf directory // FirstPart = InfDirectory; break; case DIRID_HELP: // // Help directory // lstrcpyn(Buffer,WindowsDirectory,MAX_PATH); pSetupConcatenatePaths(Buffer,TEXT("help"),MAX_PATH,NULL); FirstPart = Buffer; break; case DIRID_FONTS: // // Fonts directory // lstrcpyn(Buffer,WindowsDirectory,MAX_PATH); pSetupConcatenatePaths(Buffer,TEXT("fonts"),MAX_PATH,NULL); FirstPart = Buffer; break; case DIRID_VIEWERS: // // Viewers directory // lstrcpyn(Buffer,SystemDirectory,MAX_PATH); pSetupConcatenatePaths(Buffer,TEXT("viewers"),MAX_PATH,NULL); FirstPart = Buffer; break; case DIRID_COLOR: // // ICM directory // lstrcpyn(Buffer, SystemDirectory, MAX_PATH); if(OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { // // On NT, the path is system32\spool\drivers\color // pSetupConcatenatePaths(Buffer, TEXT("spool\\drivers\\color"), MAX_PATH, NULL); } else { // // On Win9x, the path is system\color // pSetupConcatenatePaths(Buffer, TEXT("color"), MAX_PATH, NULL); } FirstPart = Buffer; break; case DIRID_APPS: // // Application directory. // lstrcpyn(Buffer,WindowsDirectory,MAX_PATH); Buffer[2] = 0; FirstPart = Buffer; break; case DIRID_SYSTEM16: // // 16-bit system directory // FirstPart = System16Directory; break; case DIRID_SPOOL: // // spool directory // lstrcpyn(Buffer,SystemDirectory,MAX_PATH); pSetupConcatenatePaths(Buffer,TEXT("spool"),MAX_PATH,NULL); FirstPart = Buffer; break; case DIRID_SPOOLDRIVERS: b = GetPrinterDriverDirectory( NULL, // local machine NULL, // default platform 1, // structure level (PVOID)Buffer, sizeof(Buffer), (PDWORD)&Length ); if(!b) { return NULL; } FirstPart = Buffer; break; case DIRID_PRINTPROCESSOR: b = GetPrintProcessorDirectory( NULL, // local machine NULL, // default platform 1, // structure level (PVOID)Buffer, sizeof(Buffer), (PDWORD)&Length ); if(!b) { return NULL; } FirstPart = Buffer; break; case DIRID_USERPROFILE: b = GetEnvironmentVariable ( TEXT("USERPROFILE"), Buffer, MAX_PATH ); if(!b) { // // Can this happen? // return NULL; } FirstPart = Buffer; break; default: FirstPart = NULL; if((Value >= DIRID_USER) || (Value & VOLATILE_DIRID_FLAG)) { // // User-defined or volatile dirid--don't do anything with this here // except let the caller know if it's a volatile system DIRID (if // they requested this information). // if(Value < DIRID_USER && VolatileSystemDirId) { *VolatileSystemDirId = TRUE; } SetLastError(NO_ERROR); return NULL; } // // Default to system32\unknown // if(!FirstPart) { lstrcpyn(Buffer,SystemDirectory,MAX_PATH); pSetupConcatenatePaths(Buffer,TEXT("unknown"),MAX_PATH,NULL); FirstPart = Buffer; } break; } if(FirstPart) { pSetupConcatenatePaths((PTSTR)FirstPart,SubDirectory,0,&Length); Path = MyMalloc(Length * sizeof(TCHAR)); if(!Path) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } lstrcpy(Path,FirstPart); pSetupConcatenatePaths(Path,SubDirectory,Length,NULL); } else { // // Just use subdirectory. // Path = DuplicateString(SubDirectory); } // // Make sure the path doesn't end with a \. This could happen if // subdirectory is the empty string, etc. Don't do this, however, // if it's a root path (e.g., 'A:\'). // if (Path) { Length = lstrlen(Path); if(Length && *CharPrev(Path,Path+Length) == TEXT('\\')) { if((Length != 3) || (Path[1] != TEXT(':'))) { Path[Length-1] = 0; } } } return(Path); } PCTSTR pGetPathFromDirId( IN PCTSTR DirectoryId, IN PCTSTR SubDirectory, OPTIONAL IN PLOADED_INF pLoadedInf ) /* Wrapper function that merges functionality of pSetupDirectoryIdToPathEx and pSetupVolatileDirIdToPath to return the DIRID that is needed, be it regular, volatile or user defined. */ { BOOL IsVolatileDirID=FALSE; PCTSTR ReturnPath; UINT Value = 0; MYASSERT(DirectoryId); MYASSERT(pLoadedInf); if( ReturnPath = pSetupDirectoryIdToPathEx(DirectoryId, &Value, SubDirectory, pLoadedInf->InfSourcePath, NULL, &IsVolatileDirID) ){ return( ReturnPath ); } if( IsVolatileDirID || (Value >= DIRID_USER) ){ ReturnPath = pSetupVolatileDirIdToPath(DirectoryId, 0, SubDirectory, pLoadedInf); return( ReturnPath ); } // Should never happen return NULL; } PCTSTR pSetupFilenameFromLine( IN PINFCONTEXT Context, IN BOOL GetSourceName ) { return(pSetupGetField(Context,GetSourceName ? COPYSECT_SOURCE_FILENAME : COPYSECT_TARGET_FILENAME)); } #ifdef UNICODE // // ANSI version // BOOL SetupSetDirectoryIdExA( IN HINF InfHandle, IN DWORD Id, OPTIONAL IN PCSTR Directory, OPTIONAL IN DWORD Flags, IN DWORD Reserved1, IN PVOID Reserved2 ) { BOOL b; DWORD rc; PCWSTR directory; if(Directory) { rc = pSetupCaptureAndConvertAnsiArg(Directory,&directory); } else { directory = NULL; rc = NO_ERROR; } if(rc == NO_ERROR) { b = SetupSetDirectoryIdExW(InfHandle,Id,directory,Flags,Reserved1,Reserved2); rc = GetLastError(); } else { b = FALSE; } if(directory) { MyFree(directory); } SetLastError(rc); return(b); } #else // // Unicode stub // BOOL SetupSetDirectoryIdExW( IN HINF InfHandle, IN DWORD Id, OPTIONAL IN PCWSTR Directory, OPTIONAL IN DWORD Flags, IN DWORD Reserved1, IN PVOID Reserved2 ) { UNREFERENCED_PARAMETER(InfHandle); UNREFERENCED_PARAMETER(Id); UNREFERENCED_PARAMETER(Directory); UNREFERENCED_PARAMETER(Flags); UNREFERENCED_PARAMETER(Reserved1); UNREFERENCED_PARAMETER(Reserved2); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return(FALSE); } #endif BOOL SetupSetDirectoryIdEx( IN HINF InfHandle, IN DWORD Id, OPTIONAL IN PCTSTR Directory, OPTIONAL IN DWORD Flags, IN DWORD Reserved1, IN PVOID Reserved2 ) /*++ Routine Description: Associate a directory id in the user directory id range with a particular directory. The caller can use this function prior to queueing files for copy, for getting files copied to a target location known only at runtime. After setting the directory ID, this routine traverses all loaded INFs in the InfHandle's linked list, and sees if any of them have unresolved string substitutions. If so, it attempts to re-apply string substitution to them based on the new DIRID mapping. Thus, some INF values may change after calling this routine. Arguments: Id - supplies the directory id to use for the association. This value MUST be >= DIRID_USER or the function fails and GetLastError returns ERROR_INVALID_PARAMETER. If an association for this id already exists it is overwritten. If not specified (ie, 0), then Directory is ignored, and the entire current set of user-defined directory ids is deleted. Directory - if specified, supplies the directory path to associate with the given id. If not specified, any directory associated with Id is unassociated. No error results if Id is not currently associated with any directory. Flags - supplies a set of flags controlling operation. SETDIRID_NOT_FULL_PATH - indicates that the given Directory is not a full path specification but is one or more intermediate components in a path. Internally, the routine skips its usual call to GetFullPathName() if this flag is set. Return Value: Boolean value indicating outcome. If FALSE, GetLastError() returns extended error information: ERROR_NOT_ENOUGH_MEMORY: a memory allocation failed ERROR_INVALID_PARAMETER: the Id parameter is not >= DIRID_USER, or Directory is not a valid string. --*/ { PCTSTR directory; DWORD rc; PUSERDIRID UserDirId; UINT u; TCHAR Buffer[MAX_PATH]; PTSTR p; PUSERDIRID_LIST UserDirIdList; DWORD RequiredSize; // // Validate Id parameter. // Also as a special case disallow the 16-bit -1 value. // Make sure reserved params are 0. // if((Id && ((Id < DIRID_USER) || (Id == DIRID_ABSOLUTE_16BIT))) || Reserved1 || Reserved2) { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } // // Capture directory, if specified. Ignore if Id is not specified. // rc = NO_ERROR; if(Id && Directory) { try { directory = DuplicateString(Directory); } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_PARAMETER; } } else { directory = NULL; } if(rc == NO_ERROR) { if(directory) { if(Flags & SETDIRID_NOT_FULL_PATH) { lstrcpyn(Buffer, directory, MAX_PATH); MyFree(directory); } else { RequiredSize = GetFullPathName(directory, SIZECHARS(Buffer), Buffer, &p ); if(!RequiredSize) { rc = GetLastError(); } else if(RequiredSize >= SIZECHARS(Buffer)) { MYASSERT(0); rc = ERROR_BUFFER_OVERFLOW; } MyFree(directory); if(rc != NO_ERROR) { SetLastError(rc); return(FALSE); } } directory = Buffer; } } else { SetLastError(rc); return(FALSE); } try { if(!LockInf((PLOADED_INF)InfHandle)) { rc = ERROR_INVALID_HANDLE; } } except(EXCEPTION_EXECUTE_HANDLER) { rc = ERROR_INVALID_HANDLE; } if (rc != NO_ERROR) { SetLastError(rc); return(FALSE); } UserDirIdList = &(((PLOADED_INF)InfHandle)->UserDirIdList); if(Id) { // // Got an id to use. Find any existing association for it. // UserDirId = NULL; for(u = 0; u < UserDirIdList->UserDirIdCount; u++) { if(UserDirIdList->UserDirIds[u].Id == Id) { UserDirId = &(UserDirIdList->UserDirIds[u]); break; } } if(directory) { if(UserDirId) { // // Overwrite existing association. // lstrcpy(UserDirId->Directory, directory); } else { // // Add a new association at the end of the list. // UserDirId = UserDirIdList->UserDirIds ? MyRealloc(UserDirIdList->UserDirIds, (UserDirIdList->UserDirIdCount+1)*sizeof(USERDIRID)) : MyMalloc(sizeof(USERDIRID)); if(UserDirId) { UserDirIdList->UserDirIds = UserDirId; lstrcpy(UserDirIdList->UserDirIds[UserDirIdList->UserDirIdCount].Directory, directory); UserDirIdList->UserDirIds[UserDirIdList->UserDirIdCount].Id = Id; UserDirIdList->UserDirIdCount++; } else { rc = ERROR_NOT_ENOUGH_MEMORY; } } } else { // // Need to delete any existing association we found. // if(UserDirId) { // // Close up the hole in the array. // Note that when we get here u is the index of the // array slot where we found the match. // MoveMemory( &(UserDirIdList->UserDirIds[u]), &(UserDirIdList->UserDirIds[u+1]), ((UserDirIdList->UserDirIdCount-u)-1) * sizeof(USERDIRID) ); // // Try to shrink the array -- this really should never fail // but we won't fail the call if it does fail for some reason. // if(UserDirId = MyRealloc(UserDirIdList->UserDirIds, (UserDirIdList->UserDirIdCount-1)*sizeof(USERDIRID))) { UserDirIdList->UserDirIds = UserDirId; } UserDirIdList->UserDirIdCount--; } } } else { // // Id was not specified -- delete any set of associations. // if(UserDirIdList->UserDirIds) { MyFree(UserDirIdList->UserDirIds); UserDirIdList->UserDirIds = NULL; UserDirIdList->UserDirIdCount = 0; } MYASSERT(UserDirIdList->UserDirIdCount == 0); // sanity check. } if(rc == NO_ERROR) { // // Now apply new DIRID mappings to all unresolved string substitutions // in the loaded INFs. // rc = ApplyNewVolatileDirIdsToInfs((PLOADED_INF)InfHandle, NULL); } UnlockInf((PLOADED_INF)InfHandle); SetLastError(rc); return(rc == NO_ERROR); } BOOL SetupSetDirectoryIdA( IN HINF InfHandle, IN DWORD Id, OPTIONAL IN PCSTR Directory OPTIONAL ) { return(SetupSetDirectoryIdExA(InfHandle,Id,Directory,0,0,0)); } BOOL SetupSetDirectoryIdW( IN HINF InfHandle, IN DWORD Id, OPTIONAL IN PCWSTR Directory OPTIONAL ) { return(SetupSetDirectoryIdExW(InfHandle,Id,Directory,0,0,0)); } PCTSTR pSetupVolatileDirIdToPath( IN PCTSTR DirectoryId, OPTIONAL IN UINT DirectoryIdInt, OPTIONAL IN PCTSTR SubDirectory, OPTIONAL IN PLOADED_INF Inf ) /*++ Routine Description: Translate a volatile system DIRID or user-defined DIRID (along with an optional subdirectory) to an actual path. THIS ROUTINE DOES NOT DO INF LOCKING--CALLER MUST DO IT! Arguments: DirectoryId - Optionally, supplies the directory id in string form. If this parameter is not specified, then DirectoryIdInt is used directly. DirectoryIdInst - Supplies the DIRID to find the path for. This parameter is ignored if DirectoryId is supplied. SubDirectory - Optionally, supplies a subdirectory to be appended to the path specified by the given DIRID. Inf - Supplies the address of the loaded INF structure containing the user-defined DIRID values to use. Return Value: If success, a pointer to a path string is returned. The caller is responsible for freeing this memory. If failure, the return value is NULL, and GetLastError() indicates the cause of failure. --*/ { UINT Value; PTCHAR End; PCTSTR FirstPart; PTSTR Path; UINT Length; PUSERDIRID_LIST UserDirIdList; TCHAR SpecialFolderPath[MAX_PATH]; if(DirectoryId) { // // We only allow base-10 integer ids for now. // Only the terminating nul should cause the conversion to stop. // In any other case there were non-digits in the string. // Also disallow the empty string. // Value = _tcstoul(DirectoryId, &End, 10); if(*End || (End == DirectoryId)) { SetLastError(ERROR_INVALID_DATA); return(NULL); } } else { Value = DirectoryIdInt; } if(!SubDirectory) { SubDirectory = TEXT(""); } Path = NULL; FirstPart = NULL; if((Value < DIRID_USER) && (Value & VOLATILE_DIRID_FLAG)) { #ifdef ANSI_SETUPAPI { HRESULT Result; LPITEMIDLIST ppidl; Result = SHGetSpecialFolderLocation ( NULL, Value ^ VOLATILE_DIRID_FLAG, &ppidl ); if (SUCCEEDED (Result)) { if (SHGetPathFromIDList ( ppidl, SpecialFolderPath )) { FirstPart = SpecialFolderPath; } } } #else // // This is a volatile system DIRID. Presently, we only support DIRIDs // representing shell special folders, and we chose those DIRID values // to make it easy to convert to the CSIDL value necessary to hand into // SHGetSpecialFolderPath. // if(SHGetSpecialFolderPath(NULL, SpecialFolderPath, (Value ^ VOLATILE_DIRID_FLAG), TRUE // does this help? )) { FirstPart = SpecialFolderPath; } #endif } else { // // This is a user-defined DIRID--look it up in our list of user DIRIDs // presently defined. // UserDirIdList = &(Inf->UserDirIdList); for(Length = 0; Length < UserDirIdList->UserDirIdCount; Length++) { if(UserDirIdList->UserDirIds[Length].Id == Value) { FirstPart = UserDirIdList->UserDirIds[Length].Directory; break; } } } if(FirstPart) { pSetupConcatenatePaths((PTSTR)FirstPart, SubDirectory, 0, &Length); Path = MyMalloc(Length * sizeof(TCHAR)); if(!Path) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } lstrcpy(Path, FirstPart); pSetupConcatenatePaths(Path, SubDirectory, Length, NULL); } else { // // Just use subdirectory. // Path = DuplicateString(SubDirectory); } // // Make sure the path doesn't end with a \. This could happen if // subdirectory is the empty string, etc. // if (Path) { Length = lstrlen(Path); if(Length && (*CharPrev(Path,Path+Length) == TEXT('\\'))) { // // Special case when we have a path like "A:\"--we don't want // to strip the backslash in that scenario. // if((Length != 3) || (Path[1] != TEXT(':'))) { Path[Length-1] = 0; } } } return Path; } VOID InfSourcePathFromFileName( IN PCTSTR InfFileName, OUT PTSTR *SourcePath, OPTIONAL OUT PBOOL TryPnf ) /*++ Routine Description: This routine determines whether the specified INF path is in our INF search path list, or in %windir%, %windir%\INF, %windir%\system32, or %windir%\system. If so, then it returns NULL. If not, then it returns a copy of our flobal source path (which must be freed via MyFree). Arguments: InfFileName - Supplies the fully-qualified path to the INF. SourcePath - Optionally, supplies the address of a variable that receives the address of a newly-allocated buffer containing the SourcePath to use, or NULL if the default should be used. TryPnf - Supplies the address of a variable that is set upon return to indicate whether or not this INF was in one of the directories in our INF search path list. Return Value: None. --*/ { TCHAR PathBuffer[MAX_PATH]; INT TempLen; PTSTR s; if(SourcePath) { *SourcePath = NULL; } // // First, determine if this INF is located somewhere in our search path list. If so, // then there's nothing more to do. // if(!pSetupInfIsFromOemLocation(InfFileName, FALSE)) { *TryPnf = TRUE; return; } else { *TryPnf = FALSE; if(!SourcePath) { // // If the caller doesn't care about the source path, then we're done. // return; } } // // We need to use the directory path where this INF came from as our SourcePath. // lstrcpy(PathBuffer, InfFileName); s = (PTSTR)pSetupGetFileTitle(PathBuffer); if(((s - PathBuffer) == 3) && (PathBuffer[1] == TEXT(':'))) { // // This path is a root path (e.g., 'A:\'), so don't strip the trailing backslash. // *s = TEXT('\0'); } else { // // Strip the trailing backslash. // if((s > PathBuffer) && (*CharPrev(PathBuffer,s) == TEXT('\\'))) { s--; } *s = TEXT('\0'); } // // Next, see if this file exists in any of the following locations: // // %windir% // %windir%\INF // %windir%\system32 // %windir%\system // if (!lstrcmpi(PathBuffer, WindowsDirectory) || !lstrcmpi(PathBuffer, InfDirectory) || !lstrcmpi(PathBuffer, SystemDirectory) || !lstrcmpi(PathBuffer, System16Directory)) { // // It is one of the above directories--no need to use any source path // other than the default. // return; } *SourcePath = DuplicateString(PathBuffer); }