source: branches/eraser6/pluginsRewrite/Eraser.DefaultPlugins/ErasureTargets/SecureMoveErasureTarget.cs @ 2463

Revision 2463, 11.2 KB checked in by lowjoel, 2 years ago (diff)

Further compile fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26
27using System.Runtime.InteropServices;
28using System.Runtime.Serialization;
29using System.Security.Permissions;
30using System.IO;
31
32using Eraser.Util;
33using Eraser.Util.ExtensionMethods;
34using Eraser.Plugins;
35using Eraser.Plugins.ExtensionPoints;
36
37namespace Eraser.DefaultPlugins
38{
39    /// <summary>
40    /// Class representing a path that needs to be moved.
41    /// </summary>
42    [Serializable]
43    [Guid("18FB3523-4012-4718-8B9A-BADAA9084214")]
44    class SecureMoveErasureTarget : FileSystemObjectErasureTarget
45    {
46        #region Serialization code
47        protected SecureMoveErasureTarget(SerializationInfo info, StreamingContext context)
48            : base(info, context)
49        {
50            Destination = (string)info.GetValue("Destination", typeof(string));
51        }
52
53        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
54        public override void GetObjectData(SerializationInfo info, StreamingContext context)
55        {
56            base.GetObjectData(info, context);
57            info.AddValue("Destination", Destination);
58        }
59        #endregion
60
61        public SecureMoveErasureTarget()
62        {
63        }
64
65        public override Guid Guid
66        {
67            get { return GetType().GUID; }
68        }
69
70        public override string Name
71        {
72            get { return S._("Secure move"); }
73        }
74
75        public override string ToString()
76        {
77            return S._("Securely move {0}", Path);
78        }
79
80        /// <summary>
81        /// The destination of the move.
82        /// </summary>
83        public string Destination
84        {
85            get;
86            set;
87        }
88
89        public override IErasureTargetConfigurer Configurer
90        {
91            get { return new SecureMoveErasureTargetConfigurer(); }
92        }
93
94        protected override List<StreamInfo> GetPaths()
95        {
96            List<StreamInfo> result = new List<StreamInfo>();
97            if (!(File.Exists(Path) || Directory.Exists(Path)))
98                return result;
99
100            FileInfo[] files = null;
101            if ((File.GetAttributes(Path) & FileAttributes.Directory) == 0)
102                files = new FileInfo[] { new FileInfo(Path) };
103            else
104                files = GetFiles(new DirectoryInfo(Path));
105
106            foreach (FileInfo info in files)
107            {
108                //Add the alternate data streams
109                result.AddRange(GetPathADSes(info));
110
111                //And the file itself
112                result.Add(new StreamInfo(info.FullName));
113            }
114
115            return result;
116        }
117
118        public override void Execute()
119        {
120            //If the path doesn't exist, exit.
121            if (!(File.Exists(Path) || Directory.Exists(Path)))
122                return;
123
124            //Create the progress manager.
125            Progress = new SteppedProgressManager();
126            Task.Progress.Steps.Add(new SteppedProgressManagerStep(Progress,
127                1.0f / Task.Targets.Count));
128
129            try
130            {
131                //Depending on whether the path is a file or directory, execute the
132                //correct function.
133                if ((File.GetAttributes(Path) & FileAttributes.Directory) != 0)
134                {
135                    DirectoryInfo info = new DirectoryInfo(Path);
136                    CopyDirectory(info);
137                }
138                else
139                {
140                    FileInfo info = new FileInfo(Path);
141                    CopyFile(info);
142                }
143            }
144            finally
145            {
146                Progress = null;
147            }
148        }
149
150        private void CopyDirectory(DirectoryInfo info)
151        {
152            //Check the the destination is not a subfolder of the source.
153            if (PathUtil.IsRootedAt(info, Destination))
154            {
155                Logger.Log(S._("The destination directory cannot be within the source directory."),
156                    LogLevel.Error);
157                return;
158            }
159
160            //We need to get the files from the list of streams
161            List<StreamInfo> streams = GetPaths();
162            List<FileInfo> files = new List<FileInfo>(
163                streams.Distinct(new StreamInfoFileEqualityComparer()).
164                Select(x => x.File));
165            long totalSize = streams.Sum(x => x.Length);
166
167            foreach (FileInfo file in files)
168            {
169                //Compute the total size of the file on the disk (including ADSes)
170                List<StreamInfo> fileStreams = new List<StreamInfo>(file.GetADSes());
171                fileStreams.Add(new StreamInfo(file.FullName));
172                long fileSize = fileStreams.Sum(x => x.Length);
173
174                SteppedProgressManager fileProgress = new SteppedProgressManager();
175                Progress.Steps.Add(new SteppedProgressManagerStep(fileProgress,
176                    fileSize / (float)totalSize, S._("Securely moving files and folders...")));
177
178                //Add the copying step to the file progress.
179                ProgressManager copyProgress = new ProgressManager();
180                int totalPasses = 1 + EffectiveMethod.Passes;
181                fileProgress.Steps.Add(new SteppedProgressManagerStep(copyProgress,
182                    1f / totalPasses));
183
184                try
185                {
186                    //Compute the path to the new directory.
187                    DirectoryInfo sourceDirectory = file.Directory;
188                    DirectoryInfo destDirectory = new DirectoryInfo(
189                        SourceToDestinationPath(file.DirectoryName));
190
191                    //Make sure all necessary folders exist before the copy.
192                    if (!destDirectory.Exists)
193                        destDirectory.Create();
194                   
195                    //Then copy the file.
196                    file.CopyTo(System.IO.Path.Combine(destDirectory.FullName, file.Name),
197                        delegate(long TotalFileSize, long TotalBytesTransferred)
198                        {
199                            return CopyProgress(copyProgress, file, TotalFileSize,
200                                TotalBytesTransferred);
201                        });
202                }
203                catch (OperationCanceledException)
204                {
205                    //The copy was cancelled: Complete the copy part.
206                    copyProgress.MarkComplete();
207
208                    //We need to erase the partially copied copy of the file.
209                    SteppedProgressManager destroyProgress = new SteppedProgressManager();
210                    Progress.Steps.Add(new SteppedProgressManagerStep(destroyProgress, 0.5f,
211                        S._("Erasing incomplete destination file")));
212                    EraseFile(file, destroyProgress);
213
214                    //Rethrow the exception.
215                    throw;
216                }
217
218                //We copied the file over; erase the source file
219                SteppedProgressManager eraseProgress = new SteppedProgressManager();
220                fileProgress.Steps.Add(new SteppedProgressManagerStep(eraseProgress,
221                    (totalPasses - 1) / (float)totalPasses,
222                    S._("Erasing source files...")));
223                EraseFile(file, eraseProgress);
224            }
225
226            //Then copy the timestamps from the source folders and delete the source.
227            ProgressManager folderDeleteProgress = new ProgressManager();
228            Progress.Steps.Add(new SteppedProgressManagerStep(folderDeleteProgress, 0.0f,
229                S._("Removing folders...")));
230
231            Action<DirectoryInfo> CopyTimesAndDelete = null;
232            CopyTimesAndDelete = delegate(DirectoryInfo subDirectory)
233            {
234                foreach (DirectoryInfo child in subDirectory.GetDirectories())
235                    CopyTimesAndDelete(child);
236
237                //Update progress.
238                OnProgressChanged(this, new ProgressChangedEventArgs(folderDeleteProgress,
239                    new TaskProgressChangedEventArgs(subDirectory.FullName, 1, 1)));
240
241                //Get the directory which we copied to and copy the file times to the
242                //destination directory
243                DirectoryInfo destDirectory = new DirectoryInfo(
244                    SourceToDestinationPath(subDirectory.FullName));
245                if (!destDirectory.Exists)
246                    destDirectory.Create();
247                destDirectory.CopyTimes(subDirectory);
248
249                //Then delete the source directory.
250                IFileSystem fsManager = Host.Instance.FileSystems[
251                    VolumeInfo.FromMountPoint(Path)];
252                fsManager.DeleteFolder(subDirectory, true);
253            };
254            CopyTimesAndDelete(info);
255        }
256
257        /// <summary>
258        /// Converts the source path to the destination path.
259        /// </summary>
260        /// <param name="sourcePath">The source path to convert.</param>
261        /// <returns>The destination path that the file would have been moved to.</returns>
262        private string SourceToDestinationPath(string sourcePath)
263        {
264            DirectoryInfo source = new DirectoryInfo(Path);
265            string baseDir = System.IO.Path.Combine(Destination, source.Name);
266            return System.IO.Path.Combine(baseDir,
267                PathUtil.MakeRelativeTo(source, sourcePath));
268        }
269
270        private void CopyFile(FileInfo info)
271        {
272            ProgressManager copyProgress = new ProgressManager();
273            int totalPasses = 1 + EffectiveMethod.Passes;
274            Progress.Steps.Add(new SteppedProgressManagerStep(copyProgress, 1.0f / totalPasses,
275                S._("Copying source files to destination...")));
276
277            try
278            {
279                //Make sure all necessary folders exist before the copy.
280                Directory.CreateDirectory(Destination);
281
282                //Then copy the file.
283                string path = System.IO.Path.Combine(Destination, info.Name);
284                info.CopyTo(path, delegate(long TotalFileSize, long TotalBytesTransferred)
285                    {
286                        return CopyProgress(copyProgress, info, TotalFileSize,
287                            TotalBytesTransferred);
288                    });
289            }
290            catch (OperationCanceledException)
291            {
292                //The copy was cancelled: Complete the copy part.
293                copyProgress.MarkComplete();
294
295                //We need to erase the partially copied copy of the file.
296                SteppedProgressManager destroyProgress = new SteppedProgressManager();
297                Progress.Steps.Add(new SteppedProgressManagerStep(destroyProgress, 0.5f,
298                    S._("Erasing incomplete destination file")));
299                EraseFile(new FileInfo(Destination), destroyProgress);
300
301                //Rethrow the exception.
302                throw;
303            }
304
305            //Mark the copy as complete.
306            copyProgress.MarkComplete();
307
308            //Erase the source copy.
309            SteppedProgressManager eraseProgress = new SteppedProgressManager();
310            Progress.Steps.Add(new SteppedProgressManagerStep(eraseProgress,
311                (totalPasses - 1) / (float)totalPasses,
312                S._("Erasing source files...")));
313            EraseFile(info, eraseProgress);
314        }
315
316        /// <summary>
317        /// Wrapper around <see cref="FileSystemObjectErasureTarget.EraseStream"/>
318        /// that will erase every stream in the provided file.
319        /// </summary>
320        /// <param name="info">The file to erase.</param>
321        /// <param name="eraseProgress">The progress manager for the entire
322        /// erasure of the file.</param>
323        private void EraseFile(FileInfo info, SteppedProgressManager eraseProgress)
324        {
325            List<StreamInfo> streams = new List<StreamInfo>(info.GetADSes());
326            streams.Add(new StreamInfo(info.FullName));
327            long fileSize = streams.Sum(x => x.Length);
328
329            foreach (StreamInfo stream in streams)
330            {
331                ProgressManager progress = new ProgressManager();
332                eraseProgress.Steps.Add(new SteppedProgressManagerStep(progress,
333                    stream.Length / (float)fileSize,
334                    S._("Erasing incomplete destination file")));
335                EraseStream(stream, progress);
336            }
337        }
338
339        private Methods.CopyProgressFunctionResult CopyProgress(ProgressManager progress,
340            FileInfo file, long TotalFileSize, long TotalBytesTransferred) 
341        {
342            progress.Completed = TotalBytesTransferred;
343            progress.Total = TotalFileSize;
344            OnProgressChanged(this, new ProgressChangedEventArgs(Progress,
345                new TaskProgressChangedEventArgs(file.FullName, 1, 1)));
346
347            if (Task.Canceled)
348                return Methods.CopyProgressFunctionResult.Stop;
349            return Methods.CopyProgressFunctionResult.Continue;
350        }
351
352        private class StreamInfoFileEqualityComparer : IEqualityComparer<StreamInfo>
353        {
354            #region IEqualityComparer<StreamInfo> Members
355
356            public bool Equals(StreamInfo x, StreamInfo y)
357            {
358                return x.FileName == y.FileName;
359            }
360
361            public int GetHashCode(StreamInfo obj)
362            {
363                return obj.FileName.GetHashCode();
364            }
365
366            #endregion
367        }
368    }
369}
Note: See TracBrowser for help on using the repository browser.