source: branches/eraser6/pluginsRewrite/Eraser.Plugins/ExtensionPoints/IErasureMethod.cs @ 2439

Revision 2439, 11.6 KB checked in by lowjoel, 2 years ago (diff)

Make all the plugin extension points interfaces. I'll move the rest of the code tomorrow.

Line 
1/*
2 * $Id: ErasureMethod.cs 2085 2010-05-09 10:00:15Z lowjoel $
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.IO;
28using Eraser.Util;
29
30namespace Eraser.Plugins.ExtensionPoints
31{
32    /// <summary>
33    /// An interface class representing the method for erasure. If classes only
34    /// inherit this class, then the method can only be used to erase abstract
35    /// streams, not unused drive space.
36    /// </summary>
37    public abstract class IErasureMethod : IRegisterable
38    {
39        public override string ToString()
40        {
41            if (Passes == 0)
42                return Name;
43            return Passes == 1 ? S._("{0} (1 pass)", Name) :
44                S._("{0} ({1} passes)", Name, Passes);
45        }
46
47        /// <summary>
48        /// The name of this erase pass, used for display in the UI
49        /// </summary>
50        public abstract string Name
51        {
52            get;
53        }
54
55        /// <summary>
56        /// The number of erase passes for this erasure method.
57        /// </summary>
58        public abstract int Passes
59        {
60            get;
61        }
62
63        /// <summary>
64        /// The GUID for this erasure method.
65        /// </summary>
66        public abstract Guid Guid
67        {
68            get;
69        }
70
71        /// <summary>
72        /// Calculates the total size of the erasure data that needs to be written.
73        /// This is mainly for use by the Manager to determine how much data needs
74        /// to be written to disk.
75        /// </summary>
76        /// <param name="paths">The list containing the file paths to erase. This
77        /// may be null if the list of paths are unknown.</param>
78        /// <param name="targetSize">The precomputed value of the total size of
79        /// the files to be erased.</param>
80        /// <returns>The total size of the files that need to be erased.</returns>
81        /// <remarks>This function MAY be slow. Most erasure methods can
82        /// calculate this amount fairly quickly as the number of files and the
83        /// total size of the files (the ones that take most computation time)
84        /// are already provided. However some exceptional cases may take a
85        /// long time if the data set is large.</remarks>
86        public abstract long CalculateEraseDataSize(ICollection<StreamInfo> paths, long targetSize);
87
88        /// <summary>
89        /// The main bit of the class! This function is called whenever data has
90        /// to be erased. Erase the stream passed in, using the given PRNG for
91        /// randomness where necessary.
92        ///
93        /// This function should be implemented thread-safe as using the same
94        /// instance, this function may be called across different threads.
95        /// </summary>
96        /// <param name="stream">The stream which needs to be erased.</param>
97        /// <param name="erasureLength">The length of the stream to erase. If all
98        /// data in the stream should be overwritten, then pass in the maximum
99        /// value for long, the function will take the minimum.</param>
100        /// <param name="prng">The PRNG source for random data.</param>
101        /// <param name="callback">The progress callback function.</param>
102        public abstract void Erase(Stream stream, long erasureLength, IPrng prng,
103            ErasureMethodProgressFunction callback);
104
105        /// <summary>
106        /// Disk operation write unit. Chosen such that this value mod 3, 4, 512,
107        /// and 1024 is 0
108        /// </summary>
109        public const int DiskOperationUnit = 1536 * 4096;
110
111        /// <summary>
112        /// Unused space erasure file size. Each of the files used in erasing
113        /// unused space will be of this size.
114        /// </summary>
115        public const int FreeSpaceFileUnit = DiskOperationUnit * 36;
116
117        /// <summary>
118        /// Shuffles the passes in the input array, effectively randomizing the
119        /// order or rewrites.
120        /// </summary>
121        /// <param name="passes">The input set of passes.</param>
122        /// <returns>The shuffled set of passes.</returns>
123        protected static ErasureMethodPass[] ShufflePasses(ErasureMethodPass[] passes)
124        {
125            //Make a copy.
126            ErasureMethodPass[] result = new ErasureMethodPass[passes.Length];
127            passes.CopyTo(result, 0);
128
129            //Randomize.
130            IPrng rand = Host.Instance.Prngs.ActivePrng;
131            for (int i = 0; i < result.Length; ++i)
132            {
133                int val = rand.Next(result.Length - 1);
134                ErasureMethodPass tmpPass = result[val];
135                result[val] = result[i];
136                result[i] = tmpPass;
137            }
138
139            return result;
140        }
141
142        /// <summary>
143        /// Helper function. This function will write random data to the stream
144        /// using the provided PRNG.
145        /// </summary>
146        /// <param name="strm">The buffer to populate with data to write to disk.</param>
147        /// <param name="prng">The PRNG used.</param>
148        public static void WriteRandom(byte[] buffer, object value)
149        {
150            ((IPrng)value).NextBytes(buffer);
151        }
152
153        /// <summary>
154        /// Helper function. This function will write the repeating pass constant.
155        /// to the provided buffer.
156        /// </summary>
157        /// <param name="strm">The buffer to populate with data to write to disk.</param>
158        /// <param name="value">The byte[] to write.</param>
159        public static void WriteConstant(byte[] buffer, object value)
160        {
161            byte[] constant = (byte[])value;
162            for (int i = 0; i < buffer.Length; ++i)
163                buffer[i] = constant[i % constant.Length];
164        }
165
166        /// A simple callback for clients to retrieve progress information from
167        /// the erase method.
168        /// </summary>
169        /// <param name="lastWritten">The amount of data written to the stream since
170        /// the last call to the delegate.</param>
171        /// <param name="totalData">The total amount of data that must be written to
172        /// complete the erasure.</param>
173        /// <param name="currentPass">The current pass number. The total number
174        /// of passes can be found from the Passes property.</param>
175        public delegate void ErasureMethodProgressFunction(long lastWritten, long totalData,
176            int currentPass);
177    }
178
179    /// <summary>
180    /// <summary>
181    /// This class adds functionality to the ErasureMethod class to erase
182    /// unused drive space.
183    /// </summary>
184    public abstract class UnusedSpaceErasureMethod : IErasureMethod
185    {
186        /// <summary>
187        /// This function will allow clients to erase a file in a set of files
188        /// used to fill the disk, thus achieving disk unused space erasure.
189        ///
190        /// By default, this function will simply call the Erase method inherited
191        /// from the ErasureMethod class.
192        ///
193        /// This function should be implemented thread-safe as using the same
194        /// instance, this function may be called across different threads.
195        /// </summary>
196        /// <param name="strm">The stream which needs to be erased.</param>
197        /// <param name="prng">The PRNG source for random data.</param>
198        /// <param name="callback">The progress callback function.</param>
199        public virtual void EraseUnusedSpace(Stream stream, IPrng prng, ErasureMethodProgressFunction callback)
200        {
201            Erase(stream, long.MaxValue, prng, callback);
202        }
203    }
204
205    /// <summary>
206    /// Pass-based erasure method. This subclass of erasure methods follow a fixed
207    /// pattern (constant or random data) for every pass, although the order of
208    /// passes can be randomized. This is to simplify definitions of classes in
209    /// plugins.
210    ///
211    /// Since instances of this class apply data by passes, they can by default
212    /// erase unused drive space as well.
213    /// </summary>
214    public abstract class PassBasedErasureMethod : UnusedSpaceErasureMethod
215    {
216        public override int Passes
217        {
218            get { return PassesSet.Length; }
219        }
220
221        /// <summary>
222        /// Whether the passes should be randomized before running them in random
223        /// order.
224        /// </summary>
225        protected abstract bool RandomizePasses
226        {
227            get;
228        }
229
230        /// <summary>
231        /// The set of Pass objects describing the passes in this erasure method.
232        /// </summary>
233        protected abstract ErasureMethodPass[] PassesSet
234        {
235            get;
236        }
237
238        public override long CalculateEraseDataSize(ICollection<StreamInfo> paths, long targetSize)
239        {
240            //Simple. Amount of data multiplied by passes.
241            return targetSize * Passes;
242        }
243
244        public override void Erase(Stream stream, long erasureLength, IPrng prng,
245            ErasureMethodProgressFunction callback)
246        {
247            //Randomize the order of the passes
248            ErasureMethodPass[] randomizedPasses = PassesSet;
249            if (RandomizePasses)
250                randomizedPasses = ShufflePasses(randomizedPasses);
251
252            //Remember the starting position of the stream.
253            long strmStart = stream.Position;
254            long strmLength = Math.Min(stream.Length - strmStart, erasureLength);
255            long totalData = CalculateEraseDataSize(null, strmLength);
256
257            //Allocate memory for a buffer holding data for the pass.
258            byte[] buffer = new byte[Math.Min(DiskOperationUnit, strmLength)];
259
260            //Run every pass!
261            for (int pass = 0; pass < Passes; ++pass)
262            {
263                //Do a progress callback first.
264                if (callback != null)
265                    callback(0, totalData, pass + 1);
266
267                //Start from the beginning again
268                stream.Seek(strmStart, SeekOrigin.Begin);
269
270                //Write the buffer to disk.
271                long toWrite = strmLength;
272                int dataStopped = buffer.Length;
273                while (toWrite > 0)
274                {
275                    //Calculate how much of the buffer to write to disk.
276                    int amount = (int)Math.Min(toWrite, buffer.Length - dataStopped);
277
278                    //If we have no data left, get more!
279                    if (amount == 0)
280                    {
281                        randomizedPasses[pass].Execute(buffer, prng);
282                        dataStopped = 0;
283                        continue;
284                    }
285
286                    //Write the data.
287                    stream.Write(buffer, dataStopped, amount);
288                    stream.Flush();
289                    toWrite -= amount;
290
291                    //Do a progress callback.
292                    if (callback != null)
293                        callback(amount, totalData, pass + 1);
294                }
295            }
296        }
297    }
298
299    /// <summary>
300    /// A pass object. This object holds both the pass function, as well as the
301    /// data used for the pass (random, byte, or triplet)
302    /// </summary>
303    public class ErasureMethodPass
304    {
305        public override string ToString()
306        {
307            return OpaqueValue == null ? S._("Random") : OpaqueValue.ToString();
308        }
309
310        /// <summary>
311        /// Constructor.
312        /// </summary>
313        /// <param name="function">The delegate to the function.</param>
314        /// <param name="opaqueValue">The opaque value passed to the function.</param>
315        public ErasureMethodPass(ErasureMethodPassFunction function, object opaqueValue)
316        {
317            Function = function;
318            OpaqueValue = opaqueValue;
319        }
320
321        /// <summary>
322        /// Executes the pass.
323        /// </summary>
324        /// <param name="buffer">The buffer to populate with the data to write.</param>
325        /// <param name="prng">The PRNG used for random passes.</param>
326        public void Execute(byte[] buffer, IPrng prng)
327        {
328            Function(buffer, OpaqueValue == null ? prng : OpaqueValue);
329        }
330
331        /// <summary>
332        /// The function to execute for this pass.
333        /// </summary>
334        public ErasureMethodPassFunction Function { get; set; }
335
336        /// <summary>
337        /// The value to be passed to the executing function.
338        /// </summary>
339        public object OpaqueValue { get; set; }
340
341        /// <summary>
342        /// The prototype of a pass.
343        /// </summary>
344        /// <param name="strm">The buffer to populate with data to write to disk.</param>
345        /// <param name="opaque">An opaque value, depending on the type of callback.</param>
346        public delegate void ErasureMethodPassFunction(byte[] buffer, object opaque);
347    }
348}
Note: See TracBrowser for help on using the repository browser.