private void ProcessCopyFileDirective(PNPDriverINFFile pnpDriverInf, string sourceFileName, string destinationFileName) { string relativeSourcePath = PNPDriverIntegratorUtils.GetRelativeDirectoryPath(pnpDriverInf, sourceFileName, m_architectureIdentifier); FileToCopy fileToCopy = new FileToCopy(relativeSourcePath, sourceFileName, destinationFileName); if (!FileSystemUtils.IsFileExist(m_driverDirectory.Path + fileToCopy.RelativeSourceFilePath)) { Console.WriteLine("Error: Missing file: " + m_driverDirectory.Path + fileToCopy.RelativeSourceFilePath); Program.Exit(); } // actual copy will be performed later m_driverFilesToCopy.Add(fileToCopy); }
// An explanation about driver name collision in text-mode: // in text-mode, the serviceName will be determined by the name of the file, and AFAIK there is no way around it, // so in order for a driver such as the Microsoft-provided Intel E1000 to work properly (service name: E1000, filename: e1000325.sys), // we are left with two choices: // 1. create the registry entries in the wrong place, e.g. under Services\serviceFileName-without-sys-extension (e.g. Services\e1000325) // 2. rename the serviceFileName to match the correct serviceName (e.g. e1000325.sys becomes E1000.sys) // (there is also a third option to install the service under both names - but it's a really messy proposition) // the first option will work for text-mode, but will break the GUI mode later (CurrentControlSet\Enum entries will be incorrect, // and trying to overwrite them with hivesys.inf will not work AFAIK). // so we are left with the second option, it's easy to do in the case of the Intel E1000, we will simply use E1000.sys for text-mode, // the problem is when there is already a dependency that uses the file name we want to use, // the perfect example is Microsoft iSCSI initiator (service name: iScsiPrt, service filename: msiscsi.sys, dependency: iscsiprt.sys), // we want to rename msiscsi.sys to iscsiprt.sys, but there is a collision, because iscsiprt.sys is already taken by a necessary dependency, // the solution is to rename iscsiprt.sys to a different name (iscsip_o.sys), and patch(!) msiscsi.sys (which now becomes iscsiprt.sys) to use the new dependency name. // this method will test if there is a collision we will need to take care of later, and populate the needed variables. /// <param name="serviceFileName">the file name of the service executable</param> /// <param name="serviceName">The name of the service subkey under CurrentControlSet\Services</param> public void PrepareToPreventTextModeDriverNameCollision(List <DeviceService> deviceServices) { List <string> serviceFileNames = new List <string>(); List <string> expectedServiceFileNames = new List <string>(); foreach (DeviceService deviceService in deviceServices) { serviceFileNames.Add(deviceService.FileName); expectedServiceFileNames.Add(deviceService.TextModeFileName); } // we put the filenames with a name matching the service executable at the top int insertIndex = 0; for (int index = 0; index < this.DriverFilesToCopy.Count; index++) { string fileName = this.DriverFilesToCopy[index].DestinationFileName; if (StringUtils.ContainsCaseInsensitive(serviceFileNames, fileName)) { FileToCopy serviceExecutableEntry = this.DriverFilesToCopy[index]; this.DriverFilesToCopy.RemoveAt(index); this.DriverFilesToCopy.Insert(insertIndex, serviceExecutableEntry); insertIndex++; } } // now the service executables are at the top for (int index = insertIndex; index < this.DriverFilesToCopy.Count; index++) { string fileName = this.DriverFilesToCopy[index].DestinationFileName; int collisionIndex = StringUtils.IndexOfCaseInsensitive(expectedServiceFileNames, fileName); if (collisionIndex >= 0) { string serviceName = deviceServices[collisionIndex].ServiceName; string newFileName = serviceName.Substring(0, serviceName.Length - 2) + "_o.sys"; m_oldToNewFileName.Add(fileName, newFileName); Console.WriteLine("Using special measures to prevent driver naming collision"); } } }