source: branches/eraser6/pluginsRewrite/Eraser.Plugins/ExtensionPoints/ErasureMethod.cs @ 2359

Revision 2359, 11.6 KB checked in by lowjoel, 3 years ago (diff)

As far as the Plugins assembly is concerned, settings in the ManagerLibrary? are out of reach. The ManagerLibrary? will have to be the glue which pushes settings from the user to the Plugins.

As such, the PrngRegistrar? class will have internal methods to set the acting PRNG's GUID.

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 ErasureMethod : 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, Prng 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            Prng 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            ((Prng)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 : ErasureMethod
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, Prng 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, Prng 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, Prng 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.