public void UpdateDeletedAddins(IProgressStatus monitor, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
        {
            ArrayList missing = folderInfo.GetMissingAddins();

            if (missing.Count > 0)
            {
                if (Directory.Exists(folderInfo.Folder))
                {
                    scanResult.ModifiedFolderInfos.Add(folderInfo);
                }
                scanResult.ChangesFound = true;
                if (scanResult.CheckOnly)
                {
                    return;
                }

                foreach (AddinFileInfo info in missing)
                {
                    if (info.IsRoot)
                    {
                        database.UninstallRootAddin(monitor, info.AddinId, info.File, scanResult);
                    }
                    else
                    {
                        database.UninstallAddin(monitor, info.AddinId, scanResult);
                    }
                }
            }
        }
Exemple #2
0
 public void RegisterModifiedFolderInfo(AddinScanFolderInfo folderInfo)
 {
     if (!ModifiedFolderInfos.Contains(folderInfo))
     {
         ModifiedFolderInfos.Add(folderInfo);
     }
 }
Exemple #3
0
        public void AddFileToScan(string file, AddinScanFolderInfo folderInfo)
        {
            FileToScan di = new FileToScan();

            di.File = file;
            di.AddinScanFolderInfo = folderInfo;
            FilesToScan.Add(di);
            RegisterModifiedFolderInfo(folderInfo);
        }
        public static AddinScanFolderInfo Read(FileDatabase filedb, string file)
        {
            AddinScanFolderInfo finfo = (AddinScanFolderInfo)filedb.ReadSharedObject(file, typeMap);

            if (finfo != null)
            {
                finfo.fileName = file;
            }
            return(finfo);
        }
        public static AddinScanFolderInfo Read(FileDatabase filedb, string basePath, string folderPath)
        {
            string fileName;
            AddinScanFolderInfo finfo = (AddinScanFolderInfo)filedb.ReadSharedObject(basePath, GetDomain(folderPath), ".data", Path.GetFullPath(folderPath), typeMap, out fileName);

            if (finfo != null)
            {
                finfo.fileName = fileName;
            }
            return(finfo);
        }
Exemple #6
0
        public void AddFileToScan(string file, AddinScanFolderInfo folderInfo)
        {
            FileToScan di = new FileToScan();

            di.File = file;
            di.AddinScanFolderInfo = folderInfo;
            FilesToScan.Add(di);
            if (!ModifiedFolderInfos.Contains(folderInfo))
            {
                ModifiedFolderInfos.Add(folderInfo);
            }
        }
        void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanData scanData)
        {
            AddinFileInfo finfo = folderInfo.GetAddinFileInfo(file);
            bool          added = false;

            if (finfo != null && (!finfo.IsAddin || finfo.Domain == folderInfo.GetDomain(finfo.IsRoot)) && !finfo.HasChanged(FileSystem, scanData?.MD5) && !scanResult.RegenerateAllData)
            {
                if (finfo.ScanError)
                {
                    // Always schedule the file for scan if there was an error in a previous scan.
                    // However, don't set ChangesFound=true, in this way if there isn't any other
                    // change in the registry, the file won't be scanned again.
                    scanResult.AddFileToScan(file, folderInfo, scanData);
                    added = true;
                }

                if (!finfo.IsAddin)
                {
                    return;
                }

                if (database.AddinDescriptionExists(finfo.Domain, finfo.AddinId))
                {
                    // It is an add-in and it has not changed. Paths in the ignore list
                    // are still valid, so they can be used.
                    if (finfo.IgnorePaths != null)
                    {
                        scanResult.ScanContext.AddPathsToIgnore(finfo.IgnorePaths);
                    }
                    return;
                }
            }

            scanResult.ChangesFound = true;

            if (!scanResult.CheckOnly && !added)
            {
                scanResult.AddFileToScan(file, folderInfo, scanData);
            }
        }
        public void UpdateDeletedAddins(IProgressStatus monitor, AddinScanFolderInfo folderInfo)
        {
            var missing = folderInfo.GetMissingAddins(FileSystem);

            if (missing.Count > 0)
            {
                if (FileSystem.DirectoryExists(folderInfo.Folder))
                {
                    scanResult.RegisterModifiedFolderInfo(folderInfo);
                }
                scanResult.ChangesFound = true;
                if (scanResult.CheckOnly)
                {
                    return;
                }

                foreach (AddinFileInfo info in missing)
                {
                    database.UninstallAddin(monitor, info.Domain, info.AddinId, info.File, scanResult);
                }
            }
        }
        void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo)
        {
            if (scanResult.LocateAssembliesOnly)
                return;

            AddinFileInfo finfo = folderInfo.GetAddinFileInfo (file);
            bool added = false;

            if (finfo != null && (!finfo.IsAddin || finfo.Domain == folderInfo.GetDomain (finfo.IsRoot)) && fs.GetLastWriteTime (file) == finfo.LastScan && !scanResult.RegenerateAllData) {
                if (finfo.ScanError) {
                    // Always schedule the file for scan if there was an error in a previous scan.
                    // However, don't set ChangesFound=true, in this way if there isn't any other
                    // change in the registry, the file won't be scanned again.
                    scanResult.AddFileToScan (file, folderInfo);
                    added = true;
                }

                if (!finfo.IsAddin)
                    return;

                if (database.AddinDescriptionExists (finfo.Domain, finfo.AddinId)) {
                    // It is an add-in and it has not changed. Paths in the ignore list
                    // are still valid, so they can be used.
                    if (finfo.IgnorePaths != null)
                        scanResult.AddPathsToIgnore (finfo.IgnorePaths);
                    return;
                }
            }

            scanResult.ChangesFound = true;

            if (!scanResult.CheckOnly && !added)
                scanResult.AddFileToScan (file, folderInfo);
        }
Exemple #10
0
        public void UpdateDeletedAddins(IProgressStatus monitor, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
        {
            ArrayList missing = folderInfo.GetMissingAddins (fs);
            if (missing.Count > 0) {
                if (fs.DirectoryExists (folderInfo.Folder))
                    scanResult.RegisterModifiedFolderInfo (folderInfo);
                scanResult.ChangesFound = true;
                if (scanResult.CheckOnly)
                    return;

                foreach (AddinFileInfo info in missing) {
                    database.UninstallAddin (monitor, info.Domain, info.AddinId, info.File, scanResult);
                }
            }
        }
Exemple #11
0
        public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult)
        {
            path = Path.GetFullPath (path);

            // Avoid folders including each other
            if (!scanResult.VisitFolder (path))
                return;

            AddinScanFolderInfo folderInfo;
            if (!database.GetFolderInfoForPath (monitor, path, out folderInfo)) {
                // folderInfo file was corrupt.
                // Just in case, we are going to regenerate all relation data.
                if (!fs.DirectoryExists (path))
                    scanResult.RegenerateRelationData = true;
            } else {
                // Directory is included but it doesn't exist. Ignore it.
                if (folderInfo == null && !fs.DirectoryExists (path))
                    return;
            }

            // if domain is null it means that a new domain has to be created.

            bool sharedFolder = domain == AddinDatabase.GlobalDomain;
            bool isNewFolder = folderInfo == null;

            if (isNewFolder) {
                // No folder info. It is the first time this folder is scanned.
                // There is no need to store this object if the folder does not
                // contain add-ins.
                folderInfo = new AddinScanFolderInfo (path);
            }

            if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain)) {
                // If the folder already has a domain, reuse it
                if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain)
                    domain = folderInfo.RootsDomain;
                else if (domain == null) {
                    folderInfo.Domain = domain = database.GetUniqueDomainId ();
                    scanResult.RegenerateRelationData = true;
                }
                else {
                    folderInfo.Domain = domain;
                    if (!isNewFolder) {
                        // Domain has changed. Update the folder info and regenerate everything.
                        scanResult.RegenerateRelationData = true;
                        scanResult.RegisterModifiedFolderInfo (folderInfo);
                    }
                }
            }
            else if (!folderInfo.SharedFolder && sharedFolder) {
                scanResult.RegenerateRelationData = true;
            }

            folderInfo.SharedFolder = sharedFolder;

            // If there is no domain assigned to the host, get one now
            if (scanResult.Domain == AddinDatabase.UnknownDomain)
                scanResult.Domain = domain;

            // Discard folders not belonging to the required domain
            if (scanResult.Domain != null && domain != scanResult.Domain && domain != AddinDatabase.GlobalDomain) {
                return;
            }

            if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly)
                monitor.Log ("Checking: " + path);

            if (fs.DirectoryExists (path))
            {
                IEnumerable<string> files = fs.GetFiles (path);

                // First of all, look for .addin files. Addin files must be processed before
                // assemblies, because they may add files to the ignore list (i.e., assemblies
                // included in .addin files won't be scanned twice).
                foreach (string file in files) {
                    if (file.EndsWith (".addin.xml") || file.EndsWith (".addin")) {
                        RegisterFileToScan (monitor, file, scanResult, folderInfo);
                    }
                }

                // Now scan assemblies. They can also add files to the ignore list.

                foreach (string file in files) {
                    string ext = Path.GetExtension (file).ToLower ();
                    if (ext == ".dll" || ext == ".exe") {
                        RegisterFileToScan (monitor, file, scanResult, folderInfo);
                        scanResult.AddAssemblyLocation (file);
                    }
                }

                // Finally scan .addins files

                foreach (string file in files) {
                    if (Path.GetExtension (file).EndsWith (".addins")) {
                        ScanAddinsFile (monitor, file, domain, scanResult);
                    }
                }
            }
            else if (!scanResult.LocateAssembliesOnly) {
                // The folder has been deleted. All add-ins defined in that folder should also be deleted.
                scanResult.RegenerateRelationData = true;
                scanResult.ChangesFound = true;
                if (scanResult.CheckOnly)
                    return;
                database.DeleteFolderInfo (monitor, folderInfo);
            }

            if (scanResult.LocateAssembliesOnly)
                return;

            // Look for deleted add-ins.

            UpdateDeletedAddins (monitor, folderInfo, scanResult);
        }
Exemple #12
0
        public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
        {
            if (scanResult.IgnorePath (file)) {
                // The file must be ignored. Maybe it caused a crash in a previous scan, or it
                // might be included by a .addin file (in which case it will be scanned when processing
                // the .addin file).
                folderInfo.SetLastScanTime (file, null, false, fs.GetLastWriteTime (file), true);
                return;
            }

            if (monitor.LogLevel > 1)
                monitor.Log ("Scanning file: " + file);

            // Log the file to be scanned, so in case of a process crash the main process
            // will know what crashed
            monitor.Log ("plog:scan:" + file);

            string scannedAddinId = null;
            bool scannedIsRoot = false;
            bool scanSuccessful = false;
            AddinDescription config = null;

            try {
                string ext = Path.GetExtension (file).ToLower ();

                if (ext == ".dll" || ext == ".exe")
                    scanSuccessful = ScanAssembly (monitor, file, scanResult, out config);
                else
                    scanSuccessful = ScanConfigAssemblies (monitor, file, scanResult, out config);

                if (config != null) {

                    AddinFileInfo fi = folderInfo.GetAddinFileInfo (file);

                    // If version is not specified, make up one
                    if (config.Version.Length == 0) {
                        config.Version = "0.0.0.0";
                    }

                    if (config.LocalId.Length == 0) {
                        // Generate an internal id for this add-in
                        config.LocalId = database.GetUniqueAddinId (file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version);
                        config.HasUserId = false;
                    }

                    // Check errors in the description
                    StringCollection errors = config.Verify (fs);

                    if (database.IsGlobalRegistry && config.AddinId.IndexOf ('.') == -1) {
                        errors.Add ("Add-ins registered in the global registry must have a namespace.");
                    }

                    if (errors.Count > 0) {
                        scanSuccessful = false;
                        monitor.ReportError ("Errors found in add-in '" + file + ":", null);
                        foreach (string err in errors)
                            monitor.ReportError (err, null);
                    }

                    // Make sure all extensions sets are initialized with the correct add-in id

                    config.SetExtensionsAddinId (config.AddinId);

                    scanResult.ChangesFound = true;

                    // If the add-in already existed, try to reuse the relation data it had.
                    // Also, the dependencies of the old add-in need to be re-analized

                    AddinDescription existingDescription = null;
                    bool res = database.GetAddinDescription (monitor, folderInfo.Domain, config.AddinId, config.AddinFile, out existingDescription);

                    // If we can't get information about the old assembly, just regenerate all relation data
                    if (!res)
                        scanResult.RegenerateRelationData = true;

                    string replaceFileName = null;

                    if (existingDescription != null) {
                        // Reuse old relation data
                        config.MergeExternalData (existingDescription);
                        Util.AddDependencies (existingDescription, scanResult);
                        replaceFileName = existingDescription.FileName;
                    }

                    // If the scanned file results in an add-in version different from the one obtained from
                    // previous scans, the old add-in needs to be uninstalled.
                    if (fi != null && fi.IsAddin && fi.AddinId != config.AddinId) {
                        database.UninstallAddin (monitor, folderInfo.Domain, fi.AddinId, fi.File, scanResult);

                        // If the add-in version has changed, regenerate everything again since old data can't be reused
                        if (Addin.GetIdName (fi.AddinId) == Addin.GetIdName (config.AddinId))
                            scanResult.RegenerateRelationData = true;
                    }

                    // If a description could be generated, save it now (if the scan was successful)
                    if (scanSuccessful) {

                        // Assign the domain
                        if (config.IsRoot) {
                            if (folderInfo.RootsDomain == null) {
                                if (scanResult.Domain != null && scanResult.Domain != AddinDatabase.UnknownDomain && scanResult.Domain != AddinDatabase.GlobalDomain)
                                    folderInfo.RootsDomain = scanResult.Domain;
                                else
                                    folderInfo.RootsDomain = database.GetUniqueDomainId ();
                            }
                            config.Domain = folderInfo.RootsDomain;
                        } else
                            config.Domain = folderInfo.Domain;

                        if (config.IsRoot && scanResult.HostIndex != null) {
                            // If the add-in is a root, register its assemblies
                            foreach (string f in config.MainModule.Assemblies) {
                                string asmFile = Path.Combine (config.BasePath, f);
                                scanResult.HostIndex.RegisterAssembly (asmFile, config.AddinId, config.AddinFile, config.Domain);
                            }
                        }

                        // Finally save

                        if (database.SaveDescription (monitor, config, replaceFileName)) {
                            // The new dependencies also have to be updated
                            Util.AddDependencies (config, scanResult);
                            scanResult.AddAddinToUpdate (config.AddinId);
                            scannedAddinId = config.AddinId;
                            scannedIsRoot = config.IsRoot;
                            return;
                        }
                    }
                }
            }
            catch (Exception ex) {
                monitor.ReportError ("Unexpected error while scanning file: " + file, ex);
            }
            finally {
                AddinFileInfo ainfo = folderInfo.SetLastScanTime (file, scannedAddinId, scannedIsRoot, fs.GetLastWriteTime (file), !scanSuccessful);

                if (scanSuccessful && config != null) {
                    // Update the ignore list in the folder info object. To be used in the next scan
                    foreach (string df in config.AllIgnorePaths) {
                        string path = Path.Combine (config.BasePath, df);
                        ainfo.AddPathToIgnore (Path.GetFullPath (path));
                    }
                }

                monitor.Log ("plog:endscan");
            }
        }
		public void ScanFolder (IProgressStatus monitor, string path, AddinScanResult scanResult)
		{
			path = Util.GetFullPath (path);
			
			// Avoid folders including each other
			if (!scanResult.VisitFolder (path))
				return;
			
			if (monitor.VerboseLog && !scanResult.LocateAssembliesOnly)
				monitor.Log ("Checking: " + path);
			
			AddinScanFolderInfo folderInfo;
			if (!database.GetFolderInfoForPath (monitor, path, out folderInfo)) {
				// folderInfo file was corrupt.
				// Just in case, we are going to regenerate all relation data.
				if (!Directory.Exists (path))
					scanResult.RegenerateRelationData = true;
			} else {
				if (folderInfo == null && !Directory.Exists (path))
					return;
			}
			
			if (folderInfo == null)
				folderInfo = new AddinScanFolderInfo (path);
			
			if (Directory.Exists (path))
			{
				foreach (string file in Directory.GetFiles (path)) {
					if (file.EndsWith (".addin.xml")) {
						RegisterFileToScan (monitor, file, scanResult, folderInfo);
						continue;
					}
					switch (Path.GetExtension (file)) {
					case ".dll":
					case ".exe":
						RegisterFileToScan (monitor, file, scanResult, folderInfo);
						scanResult.AddAssemblyLocation (file);
						break;
					case ".addin":
						RegisterFileToScan (monitor, file, scanResult, folderInfo);
						break;
					case ".addins":
						ScanAddinsFile (monitor, file, scanResult);
						break;
					}
				}
			}
			else if (!scanResult.LocateAssembliesOnly) {
				// The folder has been deleted. All add-ins defined in that folder should also be deleted.
				scanResult.RegenerateRelationData = true;
				scanResult.ChangesFound = true;
				if (scanResult.CheckOnly)
					return;
				database.DeleteFolderInfo (monitor, folderInfo);
			}
			
			if (scanResult.LocateAssembliesOnly)
				return;
			
			// Look for deleted add-ins.
			
			UpdateDeletedAddins (monitor, folderInfo, scanResult);
		}
		public void ScanFolder (IProgressStatus monitor, string path, string domain, AddinScanResult scanResult)
		{
			path = Util.GetFullPath (path);
			
			// Avoid folders including each other
			if (!scanResult.VisitFolder (path))
				return;
			
			if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly)
				monitor.Log ("Checking: " + path);
			
			AddinScanFolderInfo folderInfo;
			if (!database.GetFolderInfoForPath (monitor, path, out folderInfo)) {
				// folderInfo file was corrupt.
				// Just in case, we are going to regenerate all relation data.
				if (!Directory.Exists (path))
					scanResult.RegenerateRelationData = true;
			} else {
				if (folderInfo == null && !Directory.Exists (path))
					return;
			}
			
			// if domain is null it means that a new domain has to be created.
			
			bool sharedFolder = domain == AddinDatabase.GlobalDomain;
			
			if (folderInfo == null)
				folderInfo = new AddinScanFolderInfo (path);
			
			if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain)) {
				// If the folder already has a domain, reuse it
				if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain)
					domain = folderInfo.RootsDomain;
				else if (domain == null) {
					folderInfo.Domain = domain = database.GetUniqueDomainId ();
					scanResult.RegenerateRelationData = true;
				}
				else {
					folderInfo.Domain = domain;
					scanResult.RegenerateRelationData = true;
				}
			}
			else if (!folderInfo.SharedFolder && sharedFolder) {
				scanResult.RegenerateRelationData = true;
			}
			
			folderInfo.SharedFolder = sharedFolder;
			
			if (Directory.Exists (path))
			{
				string[] files = Directory.GetFiles (path);
				
				// First of all, look for .addin files. Addin files must be processed before
				// assemblies, because they may add files to the ignore list (i.e., assemblies
				// included in .addin files won't be scanned twice).
				foreach (string file in files) {
					if (file.EndsWith (".addin.xml") || file.EndsWith (".addin")) {
						RegisterFileToScan (monitor, file, scanResult, folderInfo);
					}
				}
				
				foreach (string file in files) {
					switch (Path.GetExtension (file)) {
					case ".dll":
					case ".exe":
						RegisterFileToScan (monitor, file, scanResult, folderInfo);
						scanResult.AddAssemblyLocation (file);
						break;
					case ".addins":
						ScanAddinsFile (monitor, file, domain, scanResult);
						break;
					}
				}
			}
			else if (!scanResult.LocateAssembliesOnly) {
				// The folder has been deleted. All add-ins defined in that folder should also be deleted.
				scanResult.RegenerateRelationData = true;
				scanResult.ChangesFound = true;
				if (scanResult.CheckOnly)
					return;
				database.DeleteFolderInfo (monitor, folderInfo);
			}
			
			if (scanResult.LocateAssembliesOnly)
				return;
			
			// Look for deleted add-ins.
			
			UpdateDeletedAddins (monitor, folderInfo, scanResult);
		}
		public bool SaveFolderInfo (IProgressStatus monitor, AddinScanFolderInfo folderInfo)
		{
			try {
				folderInfo.Write (fileDatabase, AddinFolderCachePath);
				return true;
			}
			catch (Exception ex) {
				monitor.ReportError ("Could not write folder info file", ex);
				return false;
			}
		}
		public void UpdateDeletedAddins (IProgressStatus monitor, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
		{
			ArrayList missing = folderInfo.GetMissingAddins ();
			if (missing.Count > 0) {
				if (Directory.Exists (folderInfo.Folder))
					scanResult.ModifiedFolderInfos.Add (folderInfo);
				scanResult.ChangesFound = true;
				if (scanResult.CheckOnly)
					return;
					
				foreach (AddinFileInfo info in missing) {
					if (info.IsRoot)
						database.UninstallRootAddin (monitor, info.AddinId, info.File, scanResult);
					else
						database.UninstallAddin (monitor, info.AddinId, scanResult);
				}
			}
		}
		void RegisterFileToScan (IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo)
		{
			if (scanResult.LocateAssembliesOnly)
				return;

			AddinFileInfo finfo = folderInfo.GetAddinFileInfo (file);
			bool added = false;
			   
			if (finfo != null && File.GetLastWriteTime (file) == finfo.LastScan && !scanResult.RegenerateAllData) {
				if (finfo.ScanError) {
					// Always schedule the file for scan if there was an error in a previous scan.
					// However, don't set ChangesFound=true, in this way if there isn't any other
					// change in the registry, the file won't be scanned again.
					scanResult.AddFileToScan (file, folderInfo);
					added = true;
				}
			
				if (finfo.AddinId == null || finfo.AddinId.Length == 0)
					return;
				if (!finfo.IsRoot) {
					if (database.AddinDescriptionExists (finfo.AddinId))
						return;
				} else {
					if (database.HostDescriptionExists (finfo.AddinId, file))
						return;
				}
			}
			
			scanResult.ChangesFound = true;
			
			if (!scanResult.CheckOnly && !added)
				scanResult.AddFileToScan (file, folderInfo);
		}
 public void RegisterModifiedFolderInfo(AddinScanFolderInfo folderInfo)
 {
     if (!ModifiedFolderInfos.Contains (folderInfo))
         ModifiedFolderInfos.Add (folderInfo);
 }
 public void AddFileToScan(string file, AddinScanFolderInfo folderInfo)
 {
     FileToScan di = new FileToScan ();
     di.File = file;
     di.AddinScanFolderInfo = folderInfo;
     FilesToScan.Add (di);
     RegisterModifiedFolderInfo (folderInfo);
 }
        public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult)
        {
            path = Util.GetFullPath(path);

            // Avoid folders including each other
            if (!scanResult.VisitFolder(path))
            {
                return;
            }

            AddinScanFolderInfo folderInfo;

            if (!database.GetFolderInfoForPath(monitor, path, out folderInfo))
            {
                // folderInfo file was corrupt.
                // Just in case, we are going to regenerate all relation data.
                if (!Directory.Exists(path))
                {
                    scanResult.RegenerateRelationData = true;
                }
            }
            else
            {
                // Directory is included but it doesn't exist. Ignore it.
                if (folderInfo == null && !Directory.Exists(path))
                {
                    return;
                }
            }

            // if domain is null it means that a new domain has to be created.

            bool sharedFolder = domain == AddinDatabase.GlobalDomain;
            bool isNewFolder  = folderInfo == null;

            if (isNewFolder)
            {
                // No folder info. It is the first time this folder is scanned.
                // There is no need to store this object if the folder does not
                // contain add-ins.
                folderInfo = new AddinScanFolderInfo(path);
            }

            if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain))
            {
                // If the folder already has a domain, reuse it
                if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain)
                {
                    domain = folderInfo.RootsDomain;
                }
                else if (domain == null)
                {
                    folderInfo.Domain = domain = database.GetUniqueDomainId();
                    scanResult.RegenerateRelationData = true;
                }
                else
                {
                    folderInfo.Domain = domain;
                    if (!isNewFolder)
                    {
                        // Domain has changed. Update the folder info and regenerate everything.
                        scanResult.RegenerateRelationData = true;
                        scanResult.RegisterModifiedFolderInfo(folderInfo);
                    }
                }
            }
            else if (!folderInfo.SharedFolder && sharedFolder)
            {
                scanResult.RegenerateRelationData = true;
            }

            folderInfo.SharedFolder = sharedFolder;

            // If there is no domain assigned to the host, get one now
            if (scanResult.Domain == AddinDatabase.UnknownDomain)
            {
                scanResult.Domain = domain;
            }

            // Discard folders not belonging to the required domain
            if (scanResult.Domain != null && domain != scanResult.Domain && domain != AddinDatabase.GlobalDomain)
            {
                return;
            }

            if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly)
            {
                monitor.Log("Checking: " + path);
            }

            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path);

                // First of all, look for .addin files. Addin files must be processed before
                // assemblies, because they may add files to the ignore list (i.e., assemblies
                // included in .addin files won't be scanned twice).
                foreach (string file in files)
                {
                    if (file.EndsWith(".addin.xml") || file.EndsWith(".addin"))
                    {
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                    }
                }

                // Now scan assemblies. They can also add files to the ignore list.

                foreach (string file in files)
                {
                    string ext = Path.GetExtension(file).ToLower();
                    if (ext == ".dll" || ext == ".exe")
                    {
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                        scanResult.AddAssemblyLocation(file);
                    }
                }

                // Finally scan .addins files

                foreach (string file in files)
                {
                    if (Path.GetExtension(file).EndsWith(".addins"))
                    {
                        ScanAddinsFile(monitor, file, domain, scanResult);
                    }
                }
            }
            else if (!scanResult.LocateAssembliesOnly)
            {
                // The folder has been deleted. All add-ins defined in that folder should also be deleted.
                scanResult.RegenerateRelationData = true;
                scanResult.ChangesFound           = true;
                if (scanResult.CheckOnly)
                {
                    return;
                }
                database.DeleteFolderInfo(monitor, folderInfo);
            }

            if (scanResult.LocateAssembliesOnly)
            {
                return;
            }

            // Look for deleted add-ins.

            UpdateDeletedAddins(monitor, folderInfo, scanResult);
        }
        public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
        {
            if (scanResult.IgnorePath(file))
            {
                // The file must be ignored. Maybe it caused a crash in a previous scan, or it
                // might be included by a .addin file (in which case it will be scanned when processing
                // the .addin file).
                folderInfo.SetLastScanTime(file, null, false, File.GetLastWriteTime(file), true);
                return;
            }

            if (monitor.LogLevel > 1)
            {
                monitor.Log("Scanning file: " + file);
            }

            // Log the file to be scanned, so in case of a process crash the main process
            // will know what crashed
            monitor.Log("plog:scan:" + file);

            string           scannedAddinId = null;
            bool             scannedIsRoot  = false;
            bool             scanSuccessful = false;
            AddinDescription config         = null;

            try {
                string ext = Path.GetExtension(file);

                if (ext == ".dll" || ext == ".exe")
                {
                    scanSuccessful = ScanAssembly(monitor, file, scanResult, out config);
                }
                else
                {
                    scanSuccessful = ScanConfigAssemblies(monitor, file, scanResult, out config);
                }

                if (config != null)
                {
                    AddinFileInfo fi = folderInfo.GetAddinFileInfo(file);

                    // If version is not specified, make up one
                    if (config.Version.Length == 0)
                    {
                        config.Version = "0.0.0.0";
                    }

                    if (config.LocalId.Length == 0)
                    {
                        // Generate an internal id for this add-in
                        config.LocalId   = database.GetUniqueAddinId(file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version);
                        config.HasUserId = false;
                    }

                    // Check errors in the description
                    StringCollection errors = config.Verify();

                    if (database.IsGlobalRegistry && config.AddinId.IndexOf('.') == -1)
                    {
                        errors.Add("Add-ins registered in the global registry must have a namespace.");
                    }

                    if (errors.Count > 0)
                    {
                        scanSuccessful = false;
                        monitor.ReportError("Errors found in add-in '" + file + ":", null);
                        foreach (string err in errors)
                        {
                            monitor.ReportError(err, null);
                        }
                    }

                    // Make sure all extensions sets are initialized with the correct add-in id

                    config.SetExtensionsAddinId(config.AddinId);

                    scanResult.ChangesFound = true;

                    // If the add-in already existed, try to reuse the relation data it had.
                    // Also, the dependencies of the old add-in need to be re-analized

                    AddinDescription existingDescription = null;
                    bool             res = database.GetAddinDescription(monitor, folderInfo.Domain, config.AddinId, out existingDescription);

                    // If we can't get information about the old assembly, just regenerate all relation data
                    if (!res)
                    {
                        scanResult.RegenerateRelationData = true;
                    }

                    string replaceFileName = null;

                    if (existingDescription != null)
                    {
                        // Reuse old relation data
                        config.MergeExternalData(existingDescription);
                        Util.AddDependencies(existingDescription, scanResult);
                        replaceFileName = existingDescription.FileName;
                    }

                    // If the scanned file results in an add-in version different from the one obtained from
                    // previous scans, the old add-in needs to be uninstalled.
                    if (fi != null && fi.IsAddin && fi.AddinId != config.AddinId)
                    {
                        database.UninstallAddin(monitor, folderInfo.Domain, fi.AddinId, scanResult);

                        // If the add-in version has changed, regenerate everything again since old data can't be reused
                        if (Addin.GetIdName(fi.AddinId) == Addin.GetIdName(config.AddinId))
                        {
                            scanResult.RegenerateRelationData = true;
                        }
                    }

                    // If a description could be generated, save it now (if the scan was successful)
                    if (scanSuccessful)
                    {
                        // Assign the domain
                        if (config.IsRoot)
                        {
                            if (folderInfo.RootsDomain == null)
                            {
                                if (scanResult.Domain != null && scanResult.Domain != AddinDatabase.UnknownDomain && scanResult.Domain != AddinDatabase.GlobalDomain)
                                {
                                    folderInfo.RootsDomain = scanResult.Domain;
                                }
                                else
                                {
                                    folderInfo.RootsDomain = database.GetUniqueDomainId();
                                }
                            }
                            config.Domain = folderInfo.RootsDomain;
                        }
                        else
                        {
                            config.Domain = folderInfo.Domain;
                        }

                        if (config.IsRoot && scanResult.HostIndex != null)
                        {
                            // If the add-in is a root, register its assemblies
                            foreach (string f in config.MainModule.Assemblies)
                            {
                                string asmFile = Path.Combine(config.BasePath, f);
                                scanResult.HostIndex.RegisterAssembly(asmFile, config.AddinId, config.AddinFile, config.Domain);
                            }
                        }

                        // Finally save

                        if (database.SaveDescription(monitor, config, replaceFileName))
                        {
                            // The new dependencies also have to be updated
                            Util.AddDependencies(config, scanResult);
                            scanResult.AddAddinToUpdateRelations(config.AddinId);
                            scannedAddinId = config.AddinId;
                            scannedIsRoot  = config.IsRoot;
                            return;
                        }
                    }
                }
            }
            catch (Exception ex) {
                monitor.ReportError("Unexpected error while scanning file: " + file, ex);
            }
            finally {
                AddinFileInfo ainfo = folderInfo.SetLastScanTime(file, scannedAddinId, scannedIsRoot, File.GetLastWriteTime(file), !scanSuccessful);

                if (scanSuccessful && config != null)
                {
                    // Update the ignore list in the folder info object. To be used in the next scan
                    foreach (string df in config.AllIgnorePaths)
                    {
                        string path = Path.Combine(config.BasePath, df);
                        ainfo.AddPathToIgnore(Util.GetFullPath(path));
                    }
                }

                monitor.Log("plog:endscan");
            }
        }
		public void AddFileToScan (string file, AddinScanFolderInfo folderInfo)
		{
			FileToScan di = new FileToScan ();
			di.File = file;
			di.AddinScanFolderInfo = folderInfo;
			FilesToScan.Add (di);
			if (!ModifiedFolderInfos.Contains (folderInfo))
				ModifiedFolderInfos.Add (folderInfo);
		}
		public bool ReadFolderInfo (IProgressStatus monitor, string file, out AddinScanFolderInfo folderInfo)
		{
			try {
				folderInfo = AddinScanFolderInfo.Read (fileDatabase, file);
				return true;
			}
			catch (Exception ex) {
				folderInfo = null;
				monitor.ReportError ("Could not read folder info file", ex);
				return false;
			}
		}
		public bool GetFolderInfoForPath (IProgressStatus monitor, string path, out AddinScanFolderInfo folderInfo)
		{
			try {
				folderInfo = AddinScanFolderInfo.Read (fileDatabase, AddinFolderCachePath, path);
				return true;
			}
			catch (Exception ex) {
				folderInfo = null;
				monitor.ReportError ("Could not read folder info file", ex);
				return false;
			}
		}
        protected override void OnVisitFolder(IProgressStatus monitor, string path, string domain, bool recursive)
        {
            AddinScanFolderInfo folderInfo;

            if (!database.GetFolderInfoForPath(monitor, path, out folderInfo))
            {
                // folderInfo file was corrupt.
                // Just in case, we are going to regenerate all relation data.
                if (!FileSystem.DirectoryExists(path))
                {
                    scanResult.RegenerateRelationData = true;
                }
            }
            else
            {
                // Directory is included but it doesn't exist. Ignore it.
                if (folderInfo == null && !FileSystem.DirectoryExists(path))
                {
                    return;
                }
            }

            // if domain is null it means that a new domain has to be created.

            // Look for an add-in scan data index file. If it is present, it means the folder has been pre-scanned

            var dirScanDataIndex = AddinScanDataIndex.LoadFromFolder(monitor, path);

            if (dirScanDataIndex != null && scanResult.CleanGeneratedAddinScanDataFiles)
            {
                // Remove any existing dir.addindata if data is being generated
                dirScanDataIndex.Delete();
                dirScanDataIndex = null;
            }

            bool sharedFolder   = domain == AddinDatabase.GlobalDomain;
            bool isNewFolder    = folderInfo == null;
            bool folderHasIndex = dirScanDataIndex != null;

            if (isNewFolder)
            {
                // No folder info. It is the first time this folder is scanned.
                // There is no need to store this object if the folder does not
                // contain add-ins.
                folderInfo = new AddinScanFolderInfo(path);
                folderInfo.FolderHasScanDataIndex = folderHasIndex;
            }
            else if (folderInfo.FolderHasScanDataIndex != folderHasIndex)
            {
                // A scan data index appeared or disappeared. The information in folderInfo is not reliable.
                // Update the folder info and regenerate everything.
                scanResult.RegenerateRelationData = true;
                folderInfo.Reset();
                scanResult.RegisterModifiedFolderInfo(folderInfo);
                folderInfo.FolderHasScanDataIndex = folderHasIndex;
            }

            if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain))
            {
                // If the folder already has a domain, reuse it
                if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain)
                {
                    domain = folderInfo.RootsDomain;
                }
                else if (domain == null)
                {
                    folderInfo.Domain = domain = database.GetUniqueDomainId();
                    scanResult.RegenerateRelationData = true;
                }
                else
                {
                    folderInfo.Domain = domain;
                    if (!isNewFolder)
                    {
                        // Domain has changed. Update the folder info and regenerate everything.
                        scanResult.RegenerateRelationData = true;
                        scanResult.RegisterModifiedFolderInfo(folderInfo);
                    }
                }
            }
            else if (!folderInfo.SharedFolder && sharedFolder)
            {
                scanResult.RegenerateRelationData = true;
            }

            folderInfo.SharedFolder = sharedFolder;

            // If there is no domain assigned to the host, get one now
            if (scanResult.Domain == AddinDatabase.UnknownDomain)
            {
                scanResult.Domain = domain;
            }

            // Discard folders not belonging to the required domain
            if (scanResult.Domain != null && domain != scanResult.Domain && domain != AddinDatabase.GlobalDomain)
            {
                return;
            }

            if (monitor.LogLevel > 1)
            {
                monitor.Log("Checking: " + path);
            }

            if (dirScanDataIndex != null)
            {
                // Instead of scanning the folder, just register the files in the index
                foreach (var file in dirScanDataIndex.Files)
                {
                    RegisterFileToScan(monitor, file.FileName, folderInfo, file);
                }
                foreach (var file in dirScanDataIndex.Assemblies)
                {
                    scanResult.AssemblyIndex.AddAssemblyLocation(file);
                }
            }
            else
            {
                currentFolderInfo = folderInfo;

                base.OnVisitFolder(monitor, path, domain, recursive);

                if (!FileSystem.DirectoryExists(path))
                {
                    // The folder has been deleted. All add-ins defined in that folder should also be deleted.
                    scanResult.RegenerateRelationData = true;
                    scanResult.ChangesFound           = true;
                    if (scanResult.CheckOnly)
                    {
                        return;
                    }
                    database.DeleteFolderInfo(monitor, folderInfo);
                }
            }

            // Look for deleted add-ins.

            UpdateDeletedAddins(monitor, folderInfo);
        }
		public bool DeleteFolderInfo (IProgressStatus monitor, AddinScanFolderInfo folderInfo)
		{
			return SafeDelete (monitor, folderInfo.FileName);
		}
        public void ScanFile(IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
        {
            if (monitor.VerboseLog)
            {
                monitor.Log("Scanning file: " + file);
            }

            string scannedAddinId = null;
            bool   scannedIsRoot  = false;
            bool   scanSuccessful = false;

            try {
                string           ext    = Path.GetExtension(file);
                AddinDescription config = null;

                if (ext == ".dll" || ext == ".exe")
                {
                    scanSuccessful = ScanAssembly(monitor, file, scanResult, out config);
                }
                else
                {
                    scanSuccessful = ScanConfigAssemblies(monitor, file, scanResult, out config);
                }

                if (config != null)
                {
                    AddinFileInfo fi = folderInfo.GetAddinFileInfo(file);

                    // If version is not specified, make up one
                    if (config.Version.Length == 0)
                    {
                        config.Version = "0.0.0.0";
                    }

                    if (config.LocalId.Length == 0)
                    {
                        // Generate an internal id for this add-in
                        config.LocalId   = database.GetUniqueAddinId(file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version);
                        config.HasUserId = false;
                    }

                    // Check errors in the description
                    StringCollection errors = config.Verify();

                    if (database.IsGlobalRegistry && config.AddinId.IndexOf('.') == -1)
                    {
                        errors.Add("Add-ins registered in the global registry must have a namespace.");
                    }

                    if (errors.Count > 0)
                    {
                        scanSuccessful = false;
                        monitor.ReportError("Errors found in add-in '" + file + ":", null);
                        foreach (string err in errors)
                        {
                            monitor.ReportError(err, null);
                        }
                    }

                    // Make sure all extensions sets are initialized with the correct add-in id

                    config.SetExtensionsAddinId(config.AddinId);

                    scanResult.ChangesFound = true;

                    // If the add-in already existed, try to reuse the relation data it had.
                    // Also, the dependencies of the old add-in need to be re-analized

                    AddinDescription existingDescription = null;
                    bool             res;

                    if (config.IsRoot)
                    {
                        res = database.GetHostDescription(monitor, config.AddinId, config.AddinFile, out existingDescription);
                    }
                    else
                    {
                        res = database.GetAddinDescription(monitor, config.AddinId, out existingDescription);
                    }

                    // If we can't get information about the old assembly, just regenerate all relation data
                    if (!res)
                    {
                        scanResult.RegenerateRelationData = true;
                    }

                    string replaceFileName = null;

                    if (existingDescription != null)
                    {
                        // Reuse old relation data
                        config.MergeExternalData(existingDescription);
                        Util.AddDependencies(existingDescription, scanResult);
                        replaceFileName = existingDescription.FileName;
                    }

                    // If the scanned file results in an add-in version different from the one obtained from
                    // previous scans, the old add-in needs to be uninstalled.
                    if (fi != null && fi.AddinId != null && fi.AddinId != config.AddinId)
                    {
                        if (fi.IsRoot)
                        {
                            database.UninstallRootAddin(monitor, fi.AddinId, file, scanResult);
                        }
                        else
                        {
                            database.UninstallAddin(monitor, fi.AddinId, scanResult);
                        }

                        // If the add-in version has changed, regenerate everything again since old data can't be reused
                        if (Addin.GetIdName(fi.AddinId) == Addin.GetIdName(config.AddinId))
                        {
                            scanResult.RegenerateRelationData = true;
                        }
                    }

                    // If a description could be generated, save it now (if the scan was successful)
                    if (scanSuccessful)
                    {
                        if (database.SaveDescription(monitor, config, replaceFileName))
                        {
                            // The new dependencies also have to be updated
                            Util.AddDependencies(config, scanResult);
                            scanResult.AddAddinToUpdateRelations(config.AddinId);
                            scannedAddinId = config.AddinId;
                            scannedIsRoot  = config.IsRoot;
                            return;
                        }
                    }
                }
            }
            catch (Exception ex) {
                monitor.ReportError("Unexpected error while scanning file: " + file, ex);
            }
            finally {
                folderInfo.SetLastScanTime(file, scannedAddinId, scannedIsRoot, File.GetLastWriteTime(file), !scanSuccessful);
            }
        }
        public void ScanFolder(IProgressStatus monitor, string path, AddinScanResult scanResult)
        {
            path = Util.GetFullPath(path);

            // Avoid folders including each other
            if (!scanResult.VisitFolder(path))
            {
                return;
            }

            if (monitor.VerboseLog && !scanResult.LocateAssembliesOnly)
            {
                monitor.Log("Checking: " + path);
            }

            AddinScanFolderInfo folderInfo;

            if (!database.GetFolderInfoForPath(monitor, path, out folderInfo))
            {
                // folderInfo file was corrupt.
                // Just in case, we are going to regenerate all relation data.
                if (!Directory.Exists(path))
                {
                    scanResult.RegenerateRelationData = true;
                }
            }
            else
            {
                if (folderInfo == null && !Directory.Exists(path))
                {
                    return;
                }
            }

            if (folderInfo == null)
            {
                folderInfo = new AddinScanFolderInfo(path);
            }

            if (Directory.Exists(path))
            {
                foreach (string file in Directory.GetFiles(path))
                {
                    if (file.EndsWith(".addin.xml"))
                    {
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                        continue;
                    }
                    switch (Path.GetExtension(file))
                    {
                    case ".dll":
                    case ".exe":
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                        scanResult.AddAssemblyLocation(file);
                        break;

                    case ".addin":
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                        break;

                    case ".addins":
                        ScanAddinsFile(monitor, file, scanResult);
                        break;
                    }
                }
            }
            else if (!scanResult.LocateAssembliesOnly)
            {
                // The folder has been deleted. All add-ins defined in that folder should also be deleted.
                scanResult.RegenerateRelationData = true;
                scanResult.ChangesFound           = true;
                if (scanResult.CheckOnly)
                {
                    return;
                }
                database.DeleteFolderInfo(monitor, folderInfo);
            }

            if (scanResult.LocateAssembliesOnly)
            {
                return;
            }

            // Look for deleted add-ins.

            UpdateDeletedAddins(monitor, folderInfo, scanResult);
        }
		public void ScanFile (IProgressStatus monitor, string file, AddinScanFolderInfo folderInfo, AddinScanResult scanResult)
		{
			if (monitor.VerboseLog)
				monitor.Log ("Scanning file: " + file);
				
			string scannedAddinId = null;
			bool scannedIsRoot = false;
			bool scanSuccessful = false;
			
			try {
				string ext = Path.GetExtension (file);
				AddinDescription config = null;
				
				if (ext == ".dll" || ext == ".exe")
					scanSuccessful = ScanAssembly (monitor, file, scanResult, out config);
				else
					scanSuccessful = ScanConfigAssemblies (monitor, file, scanResult, out config);

				if (config != null) {
					
					AddinFileInfo fi = folderInfo.GetAddinFileInfo (file);
					
					// If version is not specified, make up one
					if (config.Version.Length == 0) {
						config.Version = "0.0.0.0";
					}
					
					if (config.LocalId.Length == 0) {
						// Generate an internal id for this add-in
						config.LocalId = database.GetUniqueAddinId (file, (fi != null ? fi.AddinId : null), config.Namespace, config.Version);
						config.HasUserId = false;
					}
					
					// Check errors in the description
					StringCollection errors = config.Verify ();
					
					if (database.IsGlobalRegistry && config.AddinId.IndexOf ('.') == -1) {
						errors.Add ("Add-ins registered in the global registry must have a namespace.");
					}
					    
					if (errors.Count > 0) {
						scanSuccessful = false;
						monitor.ReportError ("Errors found in add-in '" + file + ":", null);
						foreach (string err in errors)
							monitor.ReportError (err, null);
					}
				
					// Make sure all extensions sets are initialized with the correct add-in id
					
					config.SetExtensionsAddinId (config.AddinId);
					
					scanResult.ChangesFound = true;
					
					// If the add-in already existed, try to reuse the relation data it had.
					// Also, the dependencies of the old add-in need to be re-analized
					
					AddinDescription existingDescription = null;
					bool res;
					
					if (config.IsRoot)
						res = database.GetHostDescription (monitor, config.AddinId, config.AddinFile, out existingDescription);
					else
						res = database.GetAddinDescription (monitor, config.AddinId, out existingDescription);
					
					// If we can't get information about the old assembly, just regenerate all relation data
					if (!res)
						scanResult.RegenerateRelationData = true;
					
					string replaceFileName = null;
					
					if (existingDescription != null) {
						// Reuse old relation data
						config.MergeExternalData (existingDescription);
						Util.AddDependencies (existingDescription, scanResult);
						replaceFileName = existingDescription.FileName;
					}
					
					// If the scanned file results in an add-in version different from the one obtained from
					// previous scans, the old add-in needs to be uninstalled.
					if (fi != null && fi.AddinId != null && fi.AddinId != config.AddinId) {
						if (fi.IsRoot)
							database.UninstallRootAddin (monitor, fi.AddinId, file, scanResult);
						else
							database.UninstallAddin (monitor, fi.AddinId, scanResult);
						
						// If the add-in version has changed, regenerate everything again since old data can't be reused
						if (Addin.GetIdName (fi.AddinId) == Addin.GetIdName (config.AddinId))
							scanResult.RegenerateRelationData = true;
					}
					
					// If a description could be generated, save it now (if the scan was successful)
					if (scanSuccessful) {
						if (database.SaveDescription (monitor, config, replaceFileName)) {
							// The new dependencies also have to be updated
							Util.AddDependencies (config, scanResult);
							scanResult.AddAddinToUpdateRelations (config.AddinId);
							scannedAddinId = config.AddinId;
							scannedIsRoot = config.IsRoot;
							return;
						}
					}
				}
			}
			catch (Exception ex) {
				monitor.ReportError ("Unexpected error while scanning file: " + file, ex);
			}
			finally {
				folderInfo.SetLastScanTime (file, scannedAddinId, scannedIsRoot, File.GetLastWriteTime (file), !scanSuccessful);
			}
		}
Exemple #30
0
        public void ScanFolder(IProgressStatus monitor, string path, string domain, AddinScanResult scanResult)
        {
            path = Util.GetFullPath(path);

            // Avoid folders including each other
            if (!scanResult.VisitFolder(path))
            {
                return;
            }

            if (monitor.LogLevel > 1 && !scanResult.LocateAssembliesOnly)
            {
                monitor.Log("Checking: " + path);
            }

            AddinScanFolderInfo folderInfo;

            if (!database.GetFolderInfoForPath(monitor, path, out folderInfo))
            {
                // folderInfo file was corrupt.
                // Just in case, we are going to regenerate all relation data.
                if (!Directory.Exists(path))
                {
                    scanResult.RegenerateRelationData = true;
                }
            }
            else
            {
                if (folderInfo == null && !Directory.Exists(path))
                {
                    return;
                }
            }

            // if domain is null it means that a new domain has to be created.

            bool sharedFolder = domain == AddinDatabase.GlobalDomain;

            if (folderInfo == null)
            {
                folderInfo = new AddinScanFolderInfo(path);
            }

            if (!sharedFolder && (folderInfo.SharedFolder || folderInfo.Domain != domain))
            {
                // If the folder already has a domain, reuse it
                if (domain == null && folderInfo.RootsDomain != null && folderInfo.RootsDomain != AddinDatabase.GlobalDomain)
                {
                    domain = folderInfo.RootsDomain;
                }
                else if (domain == null)
                {
                    folderInfo.Domain = domain = database.GetUniqueDomainId();
                    scanResult.RegenerateRelationData = true;
                }
                else
                {
                    folderInfo.Domain = domain;
                    scanResult.RegenerateRelationData = true;
                }
            }
            else if (!folderInfo.SharedFolder && sharedFolder)
            {
                scanResult.RegenerateRelationData = true;
            }

            folderInfo.SharedFolder = sharedFolder;

            if (Directory.Exists(path))
            {
                string[] files = Directory.GetFiles(path);

                // First of all, look for .addin files. Addin files must be processed before
                // assemblies, because they may add files to the ignore list (i.e., assemblies
                // included in .addin files won't be scanned twice).
                foreach (string file in files)
                {
                    if (file.EndsWith(".addin.xml") || file.EndsWith(".addin"))
                    {
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                    }
                }

                foreach (string file in files)
                {
                    switch (Path.GetExtension(file))
                    {
                    case ".dll":
                    case ".exe":
                        RegisterFileToScan(monitor, file, scanResult, folderInfo);
                        scanResult.AddAssemblyLocation(file);
                        break;

                    case ".addins":
                        ScanAddinsFile(monitor, file, domain, scanResult);
                        break;
                    }
                }
            }
            else if (!scanResult.LocateAssembliesOnly)
            {
                // The folder has been deleted. All add-ins defined in that folder should also be deleted.
                scanResult.RegenerateRelationData = true;
                scanResult.ChangesFound           = true;
                if (scanResult.CheckOnly)
                {
                    return;
                }
                database.DeleteFolderInfo(monitor, folderInfo);
            }

            if (scanResult.LocateAssembliesOnly)
            {
                return;
            }

            // Look for deleted add-ins.

            UpdateDeletedAddins(monitor, folderInfo, scanResult);
        }
        void RegisterFileToScan(IProgressStatus monitor, string file, AddinScanResult scanResult, AddinScanFolderInfo folderInfo)
        {
            if (scanResult.LocateAssembliesOnly)
            {
                return;
            }

            AddinFileInfo finfo = folderInfo.GetAddinFileInfo(file);
            bool          added = false;

            if (finfo != null && File.GetLastWriteTime(file) == finfo.LastScan && !scanResult.RegenerateAllData)
            {
                if (finfo.ScanError)
                {
                    // Always schedule the file for scan if there was an error in a previous scan.
                    // However, don't set ChangesFound=true, in this way if there isn't any other
                    // change in the registry, the file won't be scanned again.
                    scanResult.AddFileToScan(file, folderInfo);
                    added = true;
                }

                if (finfo.AddinId == null || finfo.AddinId.Length == 0)
                {
                    return;
                }
                if (!finfo.IsRoot)
                {
                    if (database.AddinDescriptionExists(finfo.AddinId))
                    {
                        return;
                    }
                }
                else
                {
                    if (database.HostDescriptionExists(finfo.AddinId, file))
                    {
                        return;
                    }
                }
            }

            scanResult.ChangesFound = true;

            if (!scanResult.CheckOnly && !added)
            {
                scanResult.AddFileToScan(file, folderInfo);
            }
        }