<commit_before>﻿#region Disclaimer / License
// Copyright (C) 2015, The Duplicati Team
// http://www.duplicati.com, <EMAIL>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Duplicati.Library.IO;

namespace Duplicati.Library.Snapshots
{
    /// <summary>
    /// This class encapsulates all access to the Windows Volume Shadow copy Services,
    /// implementing the disposable patterns to ensure correct release of resources.
    ///
    /// The class presents all files and folders with their regular filenames to the caller,
    /// and internally handles the conversion to the shadow path.
    /// </summary>
    public sealed class WindowsSnapshot : SnapshotBase
    {
		/// <summary>
        /// The tag used for logging messages
        /// </summary>
		public static readonly string LOGTAG = Logging.Log.LogTagFromType<WindowsSnapshot>();

        /// <summary>
        /// The main reference to the backup controller
        /// </summary>
        private readonly VssBackupComponents _vssBackupComponents;

        /// <summary>
        /// Constructs a new backup snapshot, using all the required disks
        /// </summary>
        /// <param name="sources">Sources to determine which volumes to include in snapshot</param>
        /// <param name="options">A set of commandline options</param>
        public WindowsSnapshot(IEnumerable<string> sources, IDictionary<string, string> options)
        {
            try
            {
                _vssBackupComponents = new VssBackupComponents();

                // Default to exclude the System State writer
                var excludedWriters = new Guid[] { new Guid("{e8132975-6f93-4464-a53e-1050253ae220}") };
                if (options.ContainsKey("vss-exclude-writers"))
                {
                    excludedWriters = options["vss-exclude-writers"]
                        .Split(';')
                        .Where(x => !string.IsNullOrWhiteSpace(x) && x.Trim().Length > 0)
                        .Select(x => new Guid(x))
                        .ToArray();
                }
                _vssBackupComponents.SetupWriters(null, excludedWriters);

                _vssBackupComponents.InitShadowVolumes(sources);

                _vssBackupComponents.MapVolumesToSnapShots();

                //If we should map the drives, we do that now and update the volumeMap
                if (Utility.Utility.ParseBoolOption(options, "vss-use-mapping"))
                {
                    _vssBackupComponents.MapDrives();
                }
            }
            catch
            {
                //In case we fail in the constructor, we do not want a snapshot to be active
                try
                {
                    Dispose();
                }
				catch(Exception ex)
                {
					Logging.Log.WriteVerboseMessage(LOGTAG, "VSSCleanupOnError", ex, "Failed during VSS error cleanup");
                }

                throw;
            }
        }

        #region Private functions

        /// <summary>
        /// A callback function that takes a non-shadow path to a folder,
        /// and returns all folders found in a non-shadow path format.
        /// </summary>
        /// <param name="localFolderPath">The non-shadow path of the folder to list</param>
        /// <returns>A list of non-shadow paths</returns>
        protected override string[] ListFolders(string localFolderPath)
        {
            var root = Util.AppendDirSeparator(SystemIO.IO_WIN.GetPathRoot(localFolderPath));
            var volumePath = Util.AppendDirSeparator(ConvertToSnapshotPath(root));

            string[] tmp = null;
            var spath = ConvertToSnapshotPath(localFolderPath);

            if (SystemIOWindows.IsPathTooLong(spath))
            {
                try { tmp = SystemIO.IO_WIN.GetDirectories(spath); }
                catch (PathTooLongException) { }
                catch (DirectoryNotFoundException) { }
            }
            else
            {
                try { tmp = SystemIO.IO_WIN.GetDirectories(spath); }
                catch (PathTooLongException) { }
            }

            if (tmp == null)
            {
                spath = SystemIOWindows.PrefixWithUNC(spath);
                tmp = SystemIO.IO_WIN.GetDirectories(spath);
            }

            volumePath = SystemIOWindows.PrefixWithUNC(volumePath);

            for (var i = 0; i < tmp.Length; i++)
            {
                tmp[i] = root + SystemIOWindows.PrefixWithUNC(tmp[i]).Substring(volumePath.Length);
            }

            return tmp;
        }


        /// <summary>
        /// A callback function that takes a non-shadow path to a folder,
        /// and returns all files found in a non-shadow path format.
        /// </summary>
        /// <param name="localFolderPath">The non-shadow path of the folder to list</param>
        /// <returns>A list of non-shadow paths</returns>
        protected override string[] ListFiles(string localFolderPath)
        {

            string[] files = null;
            var spath = ConvertToSnapshotPath(localFolderPath);

            // First try without long UNC prefixed
            try
            {
                files = SystemIO.IO_WIN.GetFiles(spath);
            }
            catch (DirectoryNotFoundException)
            {
                spath = SystemIOWindows.PrefixWithUNC(spath);
                files = SystemIO.IO_WIN.GetFiles(spath);
            }

            // convert back to non-shadow, i.e., non-vss version
            var root = Util.AppendDirSeparator(SystemIO.IO_WIN.GetPathRoot(localFolderPath));
            var volumePath = Util.AppendDirSeparator(ConvertToSnapshotPath(root));
            volumePath = SystemIOWindows.PrefixWithUNC(volumePath);

            for (var i = 0; i < files.Length; i++)
            {
                files[i] = root + SystemIOWindows.PrefixWithUNC(files[i]).Substring(volumePath.Length);
            }

            return files;
        }
        #endregion

        #region ISnapshotService Members

        /// <summary>
        /// Gets the last write time of a given file in UTC
        /// </summary>
        /// <param name="localPath">The full path to the file in non-shadow format</param>
        /// <returns>The last write time of the file</returns>
        public override DateTime GetLastWriteTimeUtc(string localPath)
        {<commit_msg>Simplified ListFolders similarly to ListFiles.<commit_after>﻿#region Disclaimer / License
// Copyright (C) 2015, The Duplicati Team
// http://www.duplicati.com, <EMAIL>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Duplicati.Library.IO;

namespace Duplicati.Library.Snapshots
{
    /// <summary>
    /// This class encapsulates all access to the Windows Volume Shadow copy Services,
    /// implementing the disposable patterns to ensure correct release of resources.
    ///
    /// The class presents all files and folders with their regular filenames to the caller,
    /// and internally handles the conversion to the shadow path.
    /// </summary>
    public sealed class WindowsSnapshot : SnapshotBase
    {
		/// <summary>
        /// The tag used for logging messages
        /// </summary>
		public static readonly string LOGTAG = Logging.Log.LogTagFromType<WindowsSnapshot>();

        /// <summary>
        /// The main reference to the backup controller
        /// </summary>
        private readonly VssBackupComponents _vssBackupComponents;

        /// <summary>
        /// Constructs a new backup snapshot, using all the required disks
        /// </summary>
        /// <param name="sources">Sources to determine which volumes to include in snapshot</param>
        /// <param name="options">A set of commandline options</param>
        public WindowsSnapshot(IEnumerable<string> sources, IDictionary<string, string> options)
        {
            try
            {
                _vssBackupComponents = new VssBackupComponents();

                // Default to exclude the System State writer
                var excludedWriters = new Guid[] { new Guid("{e8132975-6f93-4464-a53e-1050253ae220}") };
                if (options.ContainsKey("vss-exclude-writers"))
                {
                    excludedWriters = options["vss-exclude-writers"]
                        .Split(';')
                        .Where(x => !string.IsNullOrWhiteSpace(x) && x.Trim().Length > 0)
                        .Select(x => new Guid(x))
                        .ToArray();
                }
                _vssBackupComponents.SetupWriters(null, excludedWriters);

                _vssBackupComponents.InitShadowVolumes(sources);

                _vssBackupComponents.MapVolumesToSnapShots();

                //If we should map the drives, we do that now and update the volumeMap
                if (Utility.Utility.ParseBoolOption(options, "vss-use-mapping"))
                {
                    _vssBackupComponents.MapDrives();
                }
            }
            catch
            {
                //In case we fail in the constructor, we do not want a snapshot to be active
                try
                {
                    Dispose();
                }
				catch(Exception ex)
                {
					Logging.Log.WriteVerboseMessage(LOGTAG, "VSSCleanupOnError", ex, "Failed during VSS error cleanup");
                }

                throw;
            }
        }

        #region Private functions

        /// <summary>
        /// A callback function that takes a non-shadow path to a folder,
        /// and returns all folders found in a non-shadow path format.
        /// </summary>
        /// <param name="localFolderPath">The non-shadow path of the folder to list</param>
        /// <returns>A list of non-shadow paths</returns>
        protected override string[] ListFolders(string localFolderPath)
        {
            string[] tmp = null;
            var spath = ConvertToSnapshotPath(localFolderPath);

            try
            {
                tmp = SystemIO.IO_WIN.GetDirectories(spath); 
            }
            catch (DirectoryNotFoundException) //TODO: Do we really need this??
            {
                spath = SystemIOWindows.PrefixWithUNC(spath);
                tmp = SystemIO.IO_WIN.GetDirectories(spath);
            }

            var root = Util.AppendDirSeparator(SystemIO.IO_WIN.GetPathRoot(localFolderPath));
            var volumePath = Util.AppendDirSeparator(ConvertToSnapshotPath(root));
            volumePath = SystemIOWindows.PrefixWithUNC(volumePath);

            for (var i = 0; i < tmp.Length; i++)
            {
                tmp[i] = root + SystemIOWindows.PrefixWithUNC(tmp[i]).Substring(volumePath.Length);
            }

            return tmp;
        }


        /// <summary>
        /// A callback function that takes a non-shadow path to a folder,
        /// and returns all files found in a non-shadow path format.
        /// </summary>
        /// <param name="localFolderPath">The non-shadow path of the folder to list</param>
        /// <returns>A list of non-shadow paths</returns>
        protected override string[] ListFiles(string localFolderPath)
        {

            string[] files = null;
            var spath = ConvertToSnapshotPath(localFolderPath);

            // First try without long UNC prefixed
            try
            {
                files = SystemIO.IO_WIN.GetFiles(spath);
            }
            catch (DirectoryNotFoundException) //TODO: Do we really need this??
            {
                spath = SystemIOWindows.PrefixWithUNC(spath);
                files = SystemIO.IO_WIN.GetFiles(spath);
            }

            // convert back to non-shadow, i.e., non-vss version
            var root = Util.AppendDirSeparator(SystemIO.IO_WIN.GetPathRoot(localFolderPath));
            var volumePath = Util.AppendDirSeparator(ConvertToSnapshotPath(root));
            volumePath = SystemIOWindows.PrefixWithUNC(volumePath);

            for (var i = 0; i < files.Length; i++)
            {
                files[i] = root + SystemIOWindows.PrefixWithUNC(files[i]).Substring(volumePath.Length);
            }

            return files;
        }
        #endregion

        #region ISnapshotService Members

        /// <summary>
        /// Gets the last write time of a given file in UTC
        /// </summary>
        /// <param name="localPath">The full path to the file in non-shadow format</param>
        /// <returns>The last write time of the file</returns>
        public override DateTime GetLastWriteTimeUtc(string localPath)
        {
{'fraction_non_alphanumeric': 0.09322332698681335, 'fraction_numerical': 0.006487553769127706, 'mean_word_length': 1.8656294200848655, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1682251', 'n_tokens_mistral': 3698, 'n_tokens_neox': 3513, 'n_words': 1117}