Пример #1
0
        /// <summary>
        /// Deletes the Parent directory recursively if the directories are empty
        /// This function is reentrant
        /// </summary>
        /// <param name="filePath">File name with complete path to scan recursively up the parent chain of directories</param>
        private void DeleteParentDirectoryChainIfEmpty(string filePath)
        {
            if (String.IsNullOrWhiteSpace(filePath))
            {
                return;
            }

            if (!Directory.Exists(Path.GetDirectoryName(filePath)))
            {
                return;
            }

            try
            {
                if (FilePaths.GetDirectoryFiles(Path.GetDirectoryName(filePath), "*.*", SearchOption.TopDirectoryOnly).ToList <string>().Count == 0) // there are no files in the directory
                {
                    Log.AppLog.WriteEntry(this, "Deleting directory " + Path.GetDirectoryName(filePath), Log.LogEntryType.Debug);
                    Directory.Delete(Path.GetDirectoryName(filePath));                  // Delete the directory
                    DeleteParentDirectoryChainIfEmpty(Path.GetDirectoryName(filePath)); // Kick it up one more level to check for empty directories
                }
            }
            catch (Exception ex)
            {
                Log.AppLog.WriteEntry(this, "Unable to read parent directory contents " + Path.GetDirectoryName(filePath) + "\r\n" + ex.ToString(), Log.LogEntryType.Warning);
            }
        }
Пример #2
0
        /// <summary>
        /// Scans the Monitored directories and Manual Queue for new files to process
        /// Applies the filter tests
        /// Processes conversion task jobs for the files and adds them to the queue
        /// This function takes a lock on the Queue while modifying the queue and is thread safe
        /// </summary>
        public void ScanForFiles()
        {
            // Search the specific directories
            foreach (MonitorJobOptions monitorTask in MCEBuddyConf.GlobalMCEConfig.AllMonitorTasks)
            {
                IEnumerable <string> foundFiles = null;
                try
                {
                    // Directory.EnumerateFiles throws an exception if it comes across a protected/unaccesible directory and the ENTIRE list is empty
                    // Instead we need to handle exceptions, skip the protected file/directory and continue walking down the rest
                    foundFiles = FilePaths.GetDirectoryFiles(monitorTask.searchPath, "*", (monitorTask.monitorSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)).OrderBy(File.GetLastWriteTime); // We sort the files by last modified time when scanning and adding (oldest to newest)

                    if (foundFiles != null && foundFiles.Count() > 0)                                                                                                                                                        // Check for no files (could be due to security access/protection errors
                    {
                        foreach (string foundFile in foundFiles)
                        {
                            if (GlobalDefs.Shutdown)                                    // Check for a shutdown command, this can be an intensive loop
                            {
                                return;                                                 // Exit - we're done here
                            }
                            Monitor.Enter(_monitorTaskFilterMismatchFiles);             // Make this thread safe
                            if (_monitorTaskFilterMismatchFiles.ContainsKey(foundFile)) // Check if this file has been processed by this monitor task and doesn't have a filter match, if so skip it (the filters do not change until the engine is stopped, settings changed, engine restarted which will create a new queue)
                            {
                                if (_monitorTaskFilterMismatchFiles[foundFile].Contains(monitorTask.taskName))
                                {
                                    Monitor.Exit(_monitorTaskFilterMismatchFiles);
                                    continue;
                                }
                            }
                            Monitor.Exit(_monitorTaskFilterMismatchFiles);

                            Monitor.Enter(_archivedFiles);
                            if (_archivedFiles.Contains(foundFile)) // Check if the file has been marked as an archive file if so skip it
                            {
                                Monitor.Exit(_archivedFiles);
                                continue;
                            }
                            Monitor.Exit(_archivedFiles);

                            // First check if this file if archiving is enabled and if it is in the MCEBuddyArchive or custom archive directories (which contains converted files, if so skip them)
                            if ((monitorTask.archiveMonitorOriginal ||
                                 MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archiveOriginal) &&
                                (Path.GetDirectoryName(foundFile).ToLower().Contains((string.IsNullOrEmpty(MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath) ? GlobalDefs.MCEBUDDY_ARCHIVE.ToLower() : MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath.ToLower())) || // Global archive path
                                 (Path.GetDirectoryName(foundFile).ToLower().Contains((string.IsNullOrEmpty(monitorTask.archiveMonitorPath) ? GlobalDefs.MCEBUDDY_ARCHIVE.ToLower() : monitorTask.archiveMonitorPath.ToLower())))       // Monitor task Archive path
                                ))
                            {
                                Monitor.Enter(_archivedFiles);
                                _archivedFiles.Add(foundFile); // add to the list
                                Monitor.Exit(_archivedFiles);
                                Log.AppLog.WriteEntry(this, "File " + foundFile + " is in the archive directory, skipping monitoring", Log.LogEntryType.Debug);
                                continue;
                            }

                            // 1st Level Pattern Check - Found a file, filename pattern match from monitor task
                            if (Util.Text.WildcardRegexPatternMatch(Path.GetFileName(foundFile), monitorTask.searchPattern)) // Check pattern match for Monitor Locations filter
                            {
                                // Take a lock here for EACH file before processing and modifying queue
                                // This is done per file and not for all files so that we don't lock up the engine interfaces which need the same lock to respond to GUI queries
                                // CheckAndAddFile is very intensive time consuming process for each file as it extracts metadata and compares filters
                                // Also EnumerateFiles is a very intensive process for very large nested and remote directories which will lock up the thread if the lock is taken
                                Monitor.Enter(Queue);                    // Take a lock on the queue before modifying the queue
                                CheckAndAddFile(foundFile, monitorTask); // Check history, monitor and conversion task filters and creates conversion job for file
                                Monitor.Exit(Queue);                     // Release the lock on the queue after modifying the queue
                            }
                            else // File type mismatch, log and keep track of them for each monitor task processed
                            {
                                Monitor.Enter(_monitorTaskFilterMismatchFiles);                          // Make it thread safe
                                if (!_monitorTaskFilterMismatchFiles.ContainsKey(foundFile))             /// Check if this file does not have a key, then create one
                                {
                                    _monitorTaskFilterMismatchFiles.Add(foundFile, new List <string>()); // Make a new key for the file
                                }
                                _monitorTaskFilterMismatchFiles[foundFile].Add(monitorTask.taskName);    // Add this task for the file as a filter mismatch
                                Monitor.Exit(_monitorTaskFilterMismatchFiles);

                                Log.AppLog.WriteEntry(this, "File " + Path.GetFileName(foundFile) + " did not match wildcard" + " " + monitorTask.searchPattern + " for monitor task " + monitorTask.taskName, Log.LogEntryType.Debug);
                            }
                        }
                    }
                    else
                    {
                        Log.AppLog.WriteEntry(this, "No accessible files founds in location " + monitorTask.searchPath + " for monitor task " + monitorTask.taskName, Log.LogEntryType.Information);
                    }
                }
                catch (Exception ex)
                {
                    Log.AppLog.WriteEntry(this, "Unable to search for files in location " + monitorTask.searchPath + " for monitor task " + monitorTask.taskName + "\r\nERROR : " + ex.Message, Log.LogEntryType.Warning);
                    foundFiles = null;

                    try { Monitor.Exit(Queue); } // Release queue lock
                    catch { }

                    try { Monitor.Exit(_monitorTaskFilterMismatchFiles); } // Release monitor mismatch list lock
                    catch { }

                    try { Monitor.Exit(_archivedFiles); } // Release archived list lock
                    catch { }
                }
            }

            // Read the manual queue - manual selections are always first
            Ini iniQueue = new Ini(GlobalDefs.ManualQueueFile);
            SortedList <string, string> manualQueue = iniQueue.GetSectionKeyValuePairs("ManualQueue");

            foreach (KeyValuePair <string, string> manualFile in manualQueue)
            {
                string filePath = manualFile.Value; // Due to INI restriction only the Value can hold special characters like ];= which maybe contained in the filename, hence the Value is used to capture the "TRUE" filename (Key and Section have restrictions)

                if (GlobalDefs.Shutdown)            // Check for a shutdown command, this can be an intensive loop
                {
                    return;                         // Exit - we're done here
                }
                // Check for valid entry
                if (String.IsNullOrWhiteSpace(filePath))
                {
                    continue;
                }

                string destinationPath = Path.GetDirectoryName(filePath);
                if (String.IsNullOrWhiteSpace(destinationPath)) // check for a null directory name here (happens with some root level network paths)
                {
                    iniQueue.DeleteSection(filePath);           // Remove the key from the manual file
                    continue;
                }

                // Connect network drives if needed for each manual entry
                GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions;
                if (Util.Net.IsUNCPath(destinationPath))
                {
                    if (!String.IsNullOrWhiteSpace(go.userName))
                    {
                        ConnectNet(destinationPath, go.domainName, go.userName, go.password);
                    }
                    else
                    {
                        Log.AppLog.WriteEntry(this, "No network authentication username found, defaulting to Guest authentication", Log.LogEntryType.Warning);
                        ConnectNet(destinationPath, "", GlobalDefs.DEFAULT_NETWORK_USERNAME, "");
                    }
                }

                if (Directory.Exists(filePath)) // After we are connected, check if the target is a directory (accidentally happens), we don't process it
                {
                    Log.AppLog.WriteEntry(this, "Manually selected file " + filePath + " is a directory, skipping", Log.LogEntryType.Warning);
                    iniQueue.DeleteSection(filePath); // Remove the key from the manual file
                    continue;
                }

                if (!File.Exists(filePath)) // After we are connected, check if the file actually exists
                {
                    Log.AppLog.WriteEntry(this, "Manually selected file " + filePath + " does not exist or MCEBuddy doesn't have read permissions, skipping", Log.LogEntryType.Warning);
                    iniQueue.DeleteSection(filePath); // Remove the key from the manual file
                    continue;
                }

                Log.AppLog.WriteEntry(this, "Manually selected file " + filePath + " added to queue", Log.LogEntryType.Debug);
                // Take a lock here for EACH file before processing and modifying queue
                // This is done per file and not for all files so that we don't lock up the engine interfaces which need the same lock to respond to GUI queries
                // CheckAndAddFile is very intensive time consuming process for each file as it extracts metadata and compares filters
                try
                {
                    Monitor.Enter(Queue); // Take a lock on the queue before modifying the queue
                    CheckAndAddFile(filePath, null);
                    Monitor.Exit(Queue);  // Release the lock on the queue after modifying the queue
                }
                catch (Exception ex)
                {
                    Log.AppLog.WriteEntry(this, "Add manual files terminated.\r\nERROR : " + ex.Message, Log.LogEntryType.Warning);

                    try { Monitor.Exit(Queue); } // Release queue lock
                    catch { }
                }
            }
        }