private static string GetTargetDirectory(string rootDirectory, MsiDirectory relativePath) { LessIO.Path fullPath = LessIO.Path.Combine(rootDirectory, relativePath.GetPath()); if (!FileSystem.Exists(fullPath)) { FileSystem.CreateDirectory(fullPath); } return(fullPath.PathString); }
private static DirectoryInfo GetTargetDirectory(DirectoryInfo rootDirectory, MsiDirectory relativePath) { string fullPath = Path.Combine(rootDirectory.FullName, relativePath.GetPath()); if (!Directory.Exists(fullPath)) { Directory.CreateDirectory(fullPath); } return(new DirectoryInfo(fullPath)); }
/// <summary> /// Creates a list of <see cref="MsiFile"/> objects from the specified database. /// </summary> public static MsiFile[] CreateMsiFilesFromMSI(Database msidb) { TableRow[] rows = TableRow.GetRowsFromTable(msidb, "File"); // do some prep work to cache values from MSI for finding directories later... MsiDirectory[] rootDirectories; MsiDirectory[] allDirectories; MsiDirectory.GetMsiDirectories(msidb, out rootDirectories, out allDirectories); //find the target directory for each by reviewing the Component Table TableRow[] components = TableRow.GetRowsFromTable(msidb, "Component"); //Component table: http://msdn.microsoft.com/en-us/library/aa368007(v=vs.85).aspx //build a table of components keyed by it's "Component" column value Hashtable componentsByComponentTable = new Hashtable(); foreach (TableRow component in components) { componentsByComponentTable[component.GetString("Component")] = component; } ArrayList /*<MsiFile>*/ files = new ArrayList(rows.Length); foreach (TableRow row in rows) { MsiFile file = new MsiFile(); string fileName = row.GetString("FileName"); string[] split = fileName.Split('|'); file.ShortFileName = split[0]; if (split.Length > 1) { file.LongFileName = split[1]; } else { file.LongFileName = split[0]; } file.File = row.GetString("File"); file.FileSize = row.GetInt32("FileSize"); file.Version = row.GetString("Version"); file.Component = row.GetString("Component_"); file._directory = GetDirectoryForFile(file, allDirectories, componentsByComponentTable); files.Add(file); } return((MsiFile[])files.ToArray(typeof(MsiFile))); }
/// <summary> /// Returns the full path considering it's parent directories. /// </summary> /// <returns></returns> public string GetPath() { string path = this.TargetName; MsiDirectory parent = this.Parent; while (parent != null) { //Sometimes parent is a '.' In this case, the files should be directly put into the parent of the parent. See http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx if (parent.TargetName != ".") { path = Path.Combine(parent.TargetName, path); } parent = parent.Parent; } return(path); }
private static DirectoryInfo GetTargetDirectory(DirectoryInfo rootDirectory, MsiDirectory relativePath) { if (rootDirectory == null) { throw new ArgumentNullException("rootDirectory"); } if (relativePath == null) { throw new ArgumentNullException("relativePath"); } var fullPath = Path.Combine(rootDirectory.FullName, relativePath.GetPath()); if (!Directory.Exists(fullPath)) { Directory.CreateDirectory(fullPath); } return(new DirectoryInfo(fullPath)); }
/// <summary> /// Returns the full path considering it's parent directories. /// </summary> /// <returns></returns> public string GetPath() { string path = this.TargetName; MsiDirectory parent = this.Parent; if (path == ".") { //happens in python msi Debug.Assert(parent != null, "Can't have null parent and '.' target directory."); path = parent.GetPath(); parent = null; } while (parent != null) { //Sometimes parent is a '.' In this case, the files should be directly put into the parent of the parent. See http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx if (parent.TargetName != ".") { path = Path.Combine(parent.TargetName, path); } parent = parent.Parent; } return(path); }
private static MsiDirectory GetDirectoryForFile(MsiFile file, MsiDirectory[] allDirectories, IDictionary componentsByComponentTable) { // get the component for the file TableRow componentRow = componentsByComponentTable[file.Component] as TableRow; if (componentRow == null) { Debug.Assert(false, "File '{0}' has no component entry.", file.LongFileName); return(null); } // found component, get the directory: string componentDirectory = componentRow.GetString("Directory_"); MsiDirectory directory = FindDirectoryByDirectoryKey(allDirectories, componentDirectory); if (directory != null) { //Trace.WriteLine(string.Format("Directory for '{0}' is '{1}'.", file.LongFileName, directory.GetPath())); } else { Debug.Fail(string.Format("directory not found for file '{0}'.", file.LongFileName)); } return(directory); }
private static DirectoryInfo GetTargetDirectory(DirectoryInfo rootDirectory, MsiDirectory relativePath) { string fullPath = Path.Combine(rootDirectory.FullName, relativePath.GetPath()); if (!Directory.Exists(fullPath)) { Directory.CreateDirectory(fullPath); } return new DirectoryInfo(fullPath); }
/// <summary> /// Creates a list of <see cref="MsiDirectory"/> objects from the specified database. /// </summary> /// <param name="allDirectories">All directories in the table.</param> /// <param name="msidb">The databse to get directories from.</param> /// <param name="rootDirectories"> /// Only the root directories (those with no parent). Use <see cref="MsiDirectory.Children"/> to traverse the rest of the directories. /// </param> public static void GetMsiDirectories(Database msidb, out MsiDirectory[] rootDirectories, out MsiDirectory[] allDirectories) { TableRow[] rows = TableRow.GetRowsFromTable(msidb, "Directory"); Hashtable directoriesByDirID = new Hashtable(); foreach (TableRow row in rows) { MsiDirectory directory = new MsiDirectory(); directory._defaultDir = row.GetString("DefaultDir"); if (directory._defaultDir != null && directory._defaultDir.Length > 0) { string[] split = directory._defaultDir.Split('|'); directory._shortName = split[0]; if (split.Length > 1) directory._targetName = split[1]; else directory._targetName = split[0]; //Semi colons can delmit the "target" and "sorce" names of the directory in DefaultDir, so we're going to use the Target here (in looking at MSI files, I found Target seems most meaningful. #region MSDN Docs on this Table /* From: http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx The DefaultDir column contains the directory's name (localizable)under the parent directory. By default, this is the name of both the target and source directories. To specify different source and target directory names, separate the target and source names with a colon as follows: [targetname]:[sourcename]. If the value of the Directory_Parent column is null or is equal to the Directory column, the DefaultDir column specifies the name of a root source directory. For a non-root source directory, a period (.) entered in the DefaultDir column for the source directory name or the target directory name indicates the directory should be located in its parent directory without a subdirectory. The directory names in this column may be formatted as short filename | long filename pairs. */ #endregion split = directory._shortName.Split(':'); if (split.Length > 1) { //semicolon present directory._shortName = split[0]; } split = directory._targetName.Split(':'); if (split.Length > 1) { //semicolon present directory._targetName = split[0]; directory._sourceName = split[1]; } else { directory._sourceName = directory._targetName; } } directory._directory = row.GetString("Directory"); directory._directoryParent = row.GetString("Directory_Parent"); directoriesByDirID.Add(directory.Directory, directory); } //Now we have all directories in the table, create a structure for them based on their parents. ArrayList rootDirectoriesList = new ArrayList(); foreach (MsiDirectory dir in directoriesByDirID.Values) { if (dir.DirectoryParent == null || dir.DirectoryParent.Length == 0) { rootDirectoriesList.Add(dir); continue; } MsiDirectory parent = directoriesByDirID[dir.DirectoryParent] as MsiDirectory; dir._parent = parent; parent._children.Add(dir); } // return the values: rootDirectories = (MsiDirectory[])rootDirectoriesList.ToArray(typeof(MsiDirectory)); MsiDirectory[] allDirectoriesLocal = new MsiDirectory[directoriesByDirID.Values.Count]; directoriesByDirID.Values.CopyTo(allDirectoriesLocal,0); allDirectories = allDirectoriesLocal; }
private static string GetTargetDirectory(string rootDirectory, MsiDirectory relativePath) { LessIO.Path fullPath = LessIO.Path.Combine(rootDirectory, relativePath.GetPath()); if (!FileSystem.Exists(fullPath)) { FileSystem.CreateDirectory(fullPath); } return fullPath.PathString; }
/// <summary> /// Returns the directory with the specified value for <see cref="MsiDirectory.Directory"/> or null if it cannot be found. /// </summary> /// <param name="directory_Value">The value for the sought directory's <see cref="MsiDirectory.Directory"/> column.</param> private static MsiDirectory FindDirectoryByDirectoryKey(MsiDirectory[] allDirectories, string directory_Value) { foreach (MsiDirectory dir in allDirectories) { if (0 == string.CompareOrdinal(dir.Directory, directory_Value)) { return dir; } } return null; }
private static MsiDirectory GetDirectoryForFile(MsiFile file, MsiDirectory[] allDirectories, IDictionary componentsByComponentTable) { // get the component for the file TableRow componentRow = componentsByComponentTable[file.Component] as TableRow; if (componentRow == null) { Debug.Assert(false, "File '{0}' has no component entry.", file.LongFileName); return null; } // found component, get the directory: string componentDirectory = componentRow.GetString("Directory_"); MsiDirectory directory = FindDirectoryByDirectoryKey(allDirectories, componentDirectory); if (directory != null) { //Trace.WriteLine(string.Format("Directory for '{0}' is '{1}'.", file.LongFileName, directory.GetPath())); } else { Debug.Fail(string.Format("directory not found for file '{0}'.", file.LongFileName)); } return directory; }
/// <summary> /// Creates a list of <see cref="MsiDirectory"/> objects from the specified database. /// </summary> /// <param name="allDirectories">All directories in the table.</param> /// <param name="msidb">The databse to get directories from.</param> /// <param name="rootDirectories"> /// Only the root directories (those with no parent). Use <see cref="MsiDirectory.Children"/> to traverse the rest of the directories. /// </param> public static void GetMsiDirectories(Database msidb, out MsiDirectory[] rootDirectories, out MsiDirectory[] allDirectories) { TableRow[] rows = TableRow.GetRowsFromTable(msidb, "Directory"); Hashtable directoriesByDirID = new Hashtable(); foreach (TableRow row in rows) { MsiDirectory directory = new MsiDirectory(); directory._defaultDir = row.GetString("DefaultDir"); if (directory._defaultDir != null && directory._defaultDir.Length > 0) { string[] split = directory._defaultDir.Split('|'); directory._shortName = split[0]; if (split.Length > 1) { directory._targetName = split[1]; } else { directory._targetName = split[0]; } //Semi colons can delmit the "target" and "sorce" names of the directory in DefaultDir, so we're going to use the Target here (in looking at MSI files, I found Target seems most meaningful. #region MSDN Docs on this Table /* From: http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx * The DefaultDir column contains the directory's name (localizable)under the parent directory. * By default, this is the name of both the target and source directories. * To specify different source and target directory names, separate the target and source names with a colon as follows: [targetname]:[sourcename]. * If the value of the Directory_Parent column is null or is equal to the Directory column, the DefaultDir column specifies the name of a root source directory. * For a non-root source directory, a period (.) entered in the DefaultDir column for the source directory name or the target directory name indicates the directory should be located in its parent directory without a subdirectory. * The directory names in this column may be formatted as short filename | long filename pairs. */ #endregion split = directory._shortName.Split(':'); if (split.Length > 1) { //semicolon present directory._shortName = split[0]; } split = directory._targetName.Split(':'); if (split.Length > 1) { //semicolon present directory._targetName = split[0]; directory._sourceName = split[1]; } else { directory._sourceName = directory._targetName; } } directory._directory = row.GetString("Directory"); directory._directoryParent = row.GetString("Directory_Parent"); directoriesByDirID.Add(directory.Directory, directory); } //Now we have all directories in the table, create a structure for them based on their parents. ArrayList rootDirectoriesList = new ArrayList(); foreach (MsiDirectory dir in directoriesByDirID.Values) { if (dir.DirectoryParent == null || dir.DirectoryParent.Length == 0) { rootDirectoriesList.Add(dir); continue; } MsiDirectory parent = directoriesByDirID[dir.DirectoryParent] as MsiDirectory; dir._parent = parent; parent._children.Add(dir); } // return the values: rootDirectories = (MsiDirectory[])rootDirectoriesList.ToArray(typeof(MsiDirectory)); MsiDirectory[] allDirectoriesLocal = new MsiDirectory[directoriesByDirID.Values.Count]; directoriesByDirID.Values.CopyTo(allDirectoriesLocal, 0); allDirectories = allDirectoriesLocal; }
/// <summary> /// Creates a list of <see cref="MsiDirectory"/> objects from the specified database. /// </summary> /// <param name="allDirectories">All directories in the table.</param> /// <param name="msidb">The databse to get directories from.</param> /// <param name="rootDirectories"> /// Only the root directories (those with no parent). Use <see cref="MsiDirectory.Children"/> to traverse the rest of the directories. /// </param> public static void GetMsiDirectories(Database msidb, out MsiDirectory[] rootDirectories, out MsiDirectory[] allDirectories) { TableRow[] rows = TableRow.GetRowsFromTable(msidb, "Directory"); Hashtable directoriesByDirID = new Hashtable(); foreach (TableRow row in rows) { MsiDirectory directory = new MsiDirectory(); directory._defaultDir = row.GetString("DefaultDir"); if (directory._defaultDir != null && directory._defaultDir.Length > 0) { string[] split = directory._defaultDir.Split('|'); directory._shortName = split[0]; if (split.Length > 1) { directory._targetName = split[1]; } else { directory._targetName = split[0]; } //Semi colons can delmit the "target" and "sorce" names of the directory in DefaultDir, so we're going to use the Target here (in looking at MSI files, I found Target seems most meaningful. #region MSDN Docs on this Table /* From: http://msdn.microsoft.com/en-us/library/aa368295%28VS.85%29.aspx * The DefaultDir column contains the directory's name (localizable)under the parent directory. * By default, this is the name of both the target and source directories. * To specify different source and target directory names, separate the target and source names with a colon as follows: [targetname]:[sourcename]. * If the value of the Directory_Parent column is null or is equal to the Directory column, the DefaultDir column specifies the name of a root source directory. * For a non-root source directory, a period (.) entered in the DefaultDir column for the source directory name or the target directory name indicates the directory should be located in its parent directory without a subdirectory. * The directory names in this column may be formatted as short filename | long filename pairs. */ #endregion split = directory._shortName.Split(':'); if (split.Length > 1) { //semicolon present directory._shortName = split[0]; } split = directory._targetName.Split(':'); if (split.Length > 1) { //semicolon present directory._targetName = split[0]; directory._sourceName = split[1]; } else { directory._sourceName = directory._targetName; } } directory._directory = row.GetString("Directory"); directory._directoryParent = row.GetString("Directory_Parent"); directoriesByDirID.Add(directory.Directory, directory); } // Adding directory to the table if it is specified as parent, but missing in the directories database. // This is workaround in case directories database is modify in runtime. var parentsList = directoriesByDirID.Values.OfType <MsiDirectory>().Select(v => v.DirectoryParent).Distinct().ToList(); foreach (var parent in parentsList) { if (!string.IsNullOrEmpty(parent) && !directoriesByDirID.ContainsKey(parent)) { MsiDirectory directory = new MsiDirectory() { _directoryParent = "", _directory = parent, _targetName = parent }; directoriesByDirID.Add(directory.Directory, directory); } } //Now we have all directories in the table, create a structure for them based on their parents. ArrayList rootDirectoriesList = new ArrayList(); foreach (MsiDirectory dir in directoriesByDirID.Values) { // If the value of the Directory_Parent column is null... var isRoot = string.IsNullOrEmpty(dir.DirectoryParent); // ...or is equal to the Directory column, the DefaultDir column specifies the name of a root source directory. - https://msdn.microsoft.com/en-us/library/windows/desktop/aa368295(v=vs.85).aspx if (!isRoot && string.Equals(dir.Directory, dir.DirectoryParent, StringComparison.InvariantCulture)) { isRoot = true; } if (isRoot) { rootDirectoriesList.Add(dir); continue; } MsiDirectory parent = directoriesByDirID[dir.DirectoryParent] as MsiDirectory; dir._parent = parent; parent._children.Add(dir); } // return the values: rootDirectories = (MsiDirectory[])rootDirectoriesList.ToArray(typeof(MsiDirectory)); MsiDirectory[] allDirectoriesLocal = new MsiDirectory[directoriesByDirID.Values.Count]; directoriesByDirID.Values.CopyTo(allDirectoriesLocal, 0); allDirectories = allDirectoriesLocal; }