|
Johan Martensson wrote: is there a way to completely delete a file or change the name of the file permanently so it can't be recovered.
Not really. Best you can do is just to fill the file you want to delete with garbage data and rename the file in each iteration of the overwrite. Do this several times over if you are concerned about people recovering the data. Seems like in your code, you are already doing so, there isn't much else you can do.
Just take what you have inside the if block and iterate it over x times. More times you iterate over, the more it is wiped, but also costing more time depending on file size. Here, you are going to have to weight out how many times to do this.
"Real programmers just throw a bunch of 1s and 0s at the computer to see what sticks" - Pete O'Hanlon
|
|
|
|
|
I've run some tests and it does work sometimes if I change the name of the file each time I fill it with junk but it's not worth the time it takes.
Oh well, at least the data-erasing part works.
However, I found that all it took was two lines of code on the for-loop, ones more I find there are easier ways of doing the same thing.
File.WriteAllBytes(filename, dummyBuffer);
rng.GetBytes(dummyBuffer);
|
|
|
|
|
|
Oh, and... in the file eraser I wrote for myself (in C) last June wipes the entire last sector (512 bytes), not just the part that was used by the file. This can help disguise the original length of the file.
Unless you know you'll only wipe small files I wouldn't allocate a buffer the size of the file; why not a fixed buffer size of 512 bytes?
|
|
|
|
|
Wiping the last sector might help, but I'm not sure how I would implement such a thing.
I have only worked with filestreams and I have no idea how to read/write directly to the sectors, so could you point me in a direction of how to do that?
I guess what I'm looking for now is a way to get the exact sectors that a file occupies and write to those.
From what I understand I should probably look at the W32 API functions ReadFile/WriteFile but I havent been able to find any C# examples.
|
|
|
|
|
double sectors = System.Math.Ceiling ( filelength / 512 ) ; ought to work.
Whoops, I mean 512.0
modified on Friday, January 04, 2008 12:17:33 PM
|
|
|
|
|
That gives me the total number of sectors a file occupies, right?
So I should still find a way to figure out which sectors the file occupies and find out how to write some random data do those specific sectors?
|
|
|
|
|
No, the operating system knows them.
|
|
|
|
|
So I have cleaned up the code a bit and created a fixed buffer instead (which I should have done from the start )
The wiping of the entire last sector works fine, a text-file that was 18 bytes showed up as 512 bytes when recovered, with garbage data in it of course, so thanks for that one.
But then again, having the lines below before deleting the file, it shows up as 0 bytes when recovered.
FileStream tmpStream = new FileStream(filename, FileMode.Create);
tmpStream.Close();
Now I only have to get rid of the filename that shows up when trying to recover the file.
I did try to rename it but that didn't work, I think it has to do with the fact that it's moved, is there really no other way of renaming files in C#?
Current code:
private void WipeFile(string filename, int timesToWrite)
{
if(File.Exists(filename))
{
byte[] dummyBuffer = new byte[512];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(dummyBuffer);
double filelength = new FileInfo(filename).Length;
double sectors = System.Math.Ceiling(filelength / 512);
for (int timesWritten = 0; timesWritten < timesToWrite; timesWritten++)
{
FileStream inputStream = new FileStream(filename, FileMode.Open, FileAccess.Write, FileShare.None);
int sectorsWritten = 0;
while (sectorsWritten < sectors)
{
inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
rng.GetBytes(dummyBuffer);
sectorsWritten++;
}
inputStream.Close();
}
FileStream tmpStream = new FileStream(filename, FileMode.Create);
tmpStream.Close();
File.Delete(filename);
}
}
modified on Friday, January 04, 2008 6:33:34 PM
|
|
|
|
|
Better.
Rather than opening and closing the stream each time you could set the Position back to 0. (Flushing might be required.)
I'd eliminate the needless local variable filelength (but maybe that's just me).
Shouldn't there be a way to truncate a file?
As to the filename; I suspect anyone snooping for data will bypass the FAT (or whatever) and access the disk more directly so I wouldn't be too concerned about it.
At one point I wanted to recover some files from a 5.25" floppy with a corrupted FAT. Using DOS 6 and "Function 440Dh Minor Code 61h Read Track on Logical Drive" I was able to do so.
That article to which I gave you a link talks about more advanced snooping techniquse than that.
|
|
|
|
|
The filestream has the ability to truncate...
FileStream tmpStream = new FileStream(filename, FileMode.Truncate);
tmpStream.Close();
but I get the same result using
FileStream tmpStream = new FileStream(filename, FileMode.Create);
tmpStream.Close();
I'm not really sure what the difference is, they booth create a zero-byte file.
|
|
|
|
|
I was hoping it could be truncated after it's been opened.
That second one will (may?) create the new file in a different spot on the disk.
|
|
|
|
|
After a little digging I found the FileStream.SetLength Method which truncates the file if the given value is less than the current length.
After using the code below, when trying to recover the file, I end up with a zero-byte file with the dates set to January 2037 and the space on the disc where the file used to be is filled with garbage.
So what's accomplished now is, the file is overwritten with garbage data n times, the original filesize and dates removed.
Even though the filename will keep haunting me and I'll keep looking for a solution, I believe the file is pretty much wiped out and can't be recovered with any standard methods.
private void WipeFile(string filename, int timesToWrite)
{
if(File.Exists(filename))
{
File.SetAttributes(filename, FileAttributes.Normal);
double sectors = System.Math.Ceiling(new FileInfo(filename).Length / 512.0);
byte[] dummyBuffer = new byte[512];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(dummyBuffer);
FileStream inputStream = new FileStream(filename, FileMode.Open);
for (int timesWritten = 0; timesWritten < timesToWrite; timesWritten++)
{
inputStream.Position = 0;
int sectorsWritten = 0;
while (sectorsWritten < sectors)
{
inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
rng.GetBytes(dummyBuffer);
sectorsWritten++;
}
}
inputStream.SetLength(0);
inputStream.Close();
DateTime dt = new DateTime(2037, 1, 1, 0, 0, 0);
File.SetCreationTime(filename, dt);
File.SetLastAccessTime(filename, dt);
File.SetLastWriteTime(filename, dt);
File.Delete(filename);
}
}
|
|
|
|
|
Excellent! Now I've learned something too.
Now, remove the first rng.GetBytes(dummyBuffer); and swap the lines:
<br />
inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);<br />
rng.GetBytes(dummyBuffer);<br />
Perhaps use a for loop rather than a while loop (both loops might as well be the same type as they do similar things).
|
|
|
|
|
|
Hello,
I have the following code in one of my projects:
DragDropHelper Helper = new DragDropHelper(); // See below!
IDragSourceHelper Drag = (IDragSourceHelper)Helper;
SHDRAGIMAGE tt = new SHDRAGIMAGE();
Bitmap img = new Bitmap(@"C:\Temp\DragImage.bmp");
tt.ptOffset.x = 0;
tt.ptOffset.y = 0;
tt.sizeDragImage.x = img.Width;
tt.sizeDragImage.y = img.Height;
tt.hbmpDragImage = img.GetHbitmap();
tt.crColorKey = 0;
Drag.InitializeFromBitmap(ref tt, dragObject);
Calling InitializeFromBitmap fails with the above mentioned message.
Can any one tell me why?
In addition, this code is in my project as well:
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct SHDRAGIMAGE
{
public POINT sizeDragImage;
public POINT ptOffset;
public IntPtr hbmpDragImage;
public uint crColorKey;
}
[ComImport, Guid("DE5BF786-477A-11d2-839D-00C04FD918D0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDragSourceHelper
{
void InitializeFromBitmap(
ref SHDRAGIMAGE pshdi,
[MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IDataObject pDataObject);
void InitializeFromWindow(
IntPtr hwnd,
ref POINT point,
[MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IDataObject pDataObject);
}
[ComImport, Guid("4657278B-411B-11d2-839A-00C04FD918D0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDropTargetHelper
{
void DragEnter(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IDataObject pDataObject, ref POINT point, DragDropEffects dwEffect);
void DragLeave();
void DragOver(ref POINT point, DragDropEffects dwEffect);
void Drop([MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IDataObject pDataObject, ref POINT point, DragDropEffects dwEffect);
void Show([MarshalAs(UnmanagedType.Bool)] bool fShow);
}
[ComImport, Guid("4657278A-411B-11d2-839A-00C04FD918D0")]
class DragDropHelper
{
}
|
|
|
|
|
If I've read your code and problem right, the problem became clear. The method or operation is not implemented.
Now to be serious, MSDN reports that the minimal dll version is shell32.dll v5.0. Do you meet this requirement? Does marshaling IDragSourceHelper require you to define the GetData() method? Not sure myself.
Just because we can; does not mean we should.
|
|
|
|
|
Thanks for your reply.
Meanwhile I've come a lot further. The problem was that methods SetData and GetData where not implemented. Therefore I created a new DataObject class which re-implements these methods. This is the code I have so far which is working but needs some adjustments here and there. Also I'm not sure whether all allocated objects are released correctly.
Regards,
Kees
public partial class CustomControl1 : Control
{
DragDropHelper Helper;
public CustomControl1()
{
InitializeComponent();
this.AllowDrop = true;
}
protected override void OnPaint(PaintEventArgs pe)
{
Brush B = new SolidBrush(Color.White);
pe.Graphics.FillRectangle(B, pe.ClipRectangle);
}
protected override void OnMouseDown(MouseEventArgs e)
{
DataFormats.Format ganttbarFormat = DataFormats.GetFormat("Ganttbar");
object ganttbar = new object();
DataObject dragObject = new DataObjectEx(ganttbarFormat.Name, ganttbar);
DoDragDrop(dragObject, DragDropEffects.All);
}
private void UpdateDragImage(System.Runtime.InteropServices.ComTypes.IDataObject dragObject)
{
if (Helper == null)
{
Helper = new DragDropHelper();
}
IDragSourceHelper Drag = (IDragSourceHelper)Helper;
SHDRAGIMAGE tt = new SHDRAGIMAGE();
Bitmap img = new Bitmap(@"C:\Temp\DragImage.bmp");
tt.ptOffset.x = 0;
tt.ptOffset.y = 0;
tt.sizeDragImage.x = img.Width;
tt.sizeDragImage.y = img.Height;
tt.hbmpDragImage = img.GetHbitmap();
tt.crColorKey = 0;
Drag.InitializeFromBitmap(ref tt, dragObject);
}
protected override void OnDragOver(DragEventArgs drgevent)
{
IDropTargetHelper H = (IDropTargetHelper)Helper;
POINT p = new POINT();
p.x = drgevent.X;
p.y = drgevent.Y;
H.DragOver(ref p, DragDropEffects.Copy);
drgevent.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
System.Runtime.InteropServices.ComTypes.IDataObject dragObject =
(System.Runtime.InteropServices.ComTypes.IDataObject)drgevent.Data;
IDropTargetHelper H = (IDropTargetHelper)Helper;
POINT p = new POINT();
p.x = drgevent.X;
p.y = drgevent.Y;
H.Drop(dragObject, ref p, DragDropEffects.Copy);
base.OnDragDrop(drgevent);
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
System.Runtime.InteropServices.ComTypes.IDataObject dragObject =
(System.Runtime.InteropServices.ComTypes.IDataObject)drgevent.Data;
UpdateDragImage(dragObject);
IDropTargetHelper H = (IDropTargetHelper)Helper;
POINT p = new POINT();
p.x = drgevent.X;
p.y = drgevent.Y;
H.DragEnter(Handle, dragObject, ref p, DragDropEffects.Copy);
drgevent.Effect = DragDropEffects.Copy;
}
protected override void OnDragLeave(EventArgs e)
{
IDropTargetHelper H = (IDropTargetHelper)Helper;
H.DragLeave();
base.OnDragLeave(e);
}
protected override void OnGiveFeedback(GiveFeedbackEventArgs gfbevent)
{
// base.OnGiveFeedback(gfbevent);
}
protected override void OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent)
{
if (qcdevent.EscapePressed == true)
{
qcdevent.Action = DragAction.Cancel;
}
// base.OnQueryContinueDrag(qcdevent);
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct SHDRAGIMAGE
{
public POINT sizeDragImage;
public POINT ptOffset;
public IntPtr hbmpDragImage;
public uint crColorKey;
}
[ComImport, Guid("DE5BF786-477A-11d2-839D-00C04FD918D0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDragSourceHelper
{
void InitializeFromBitmap(
ref SHDRAGIMAGE pshdi,
[MarshalAs(UnmanagedType.Interface)]
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject);
void InitializeFromWindow(
IntPtr hwnd,
ref POINT point,
[MarshalAs(UnmanagedType.Interface)]
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject);
}
[ComImport, Guid("4657278B-411B-11d2-839A-00C04FD918D0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDropTargetHelper
{
void DragEnter(
IntPtr hwnd,
[MarshalAs(UnmanagedType.Interface)]
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject,
ref POINT point,
DragDropEffects dwEffect);
void DragLeave();
void DragOver(ref POINT point, DragDropEffects dwEffect);
void Drop(
[MarshalAs(UnmanagedType.Interface)]
System.Runtime.InteropServices.ComTypes.IDataObject pDataObject,
ref POINT point,
DragDropEffects dwEffect);
void Show([MarshalAs(UnmanagedType.Bool)] bool fShow);
}
[ComImport, Guid("4657278A-411B-11d2-839A-00C04FD918D0")]
class DragDropHelper
{
}
public class FormatetDataObject
{
public FORMATETC format;
public STGMEDIUM medium;
}
public class DataObjectEx : DataObject, System.Runtime.InteropServices.ComTypes.IDataObject
{
public DataObjectEx(string format, object data)
: base(format, data)
{
}
public void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release)
{
string s = formatIn.tymed.ToString() + formatIn.cfFormat.ToString();
FormatetDataObject dataObject = new FormatetDataObject();
dataObject.format = formatIn;
dataObject.medium = medium;
base.SetData(s, dataObject);
}
public void GetData(ref FORMATETC format, out STGMEDIUM medium)
{
string key = format.tymed.ToString() + format.dwAspect.ToString() + format.cfFormat.ToString();
FormatetDataObject dataObject;
dataObject = (FormatetDataObject)base.GetData(key);
if (dataObject != null)
{
System.Diagnostics.Debug.Assert(format.cfFormat == dataObject.format.cfFormat &&
format.dwAspect == dataObject.format.dwAspect &&
format.tymed == dataObject.format.tymed);
medium = dataObject.medium;
}
else
//
// return empty medium
//
{
STGMEDIUM m;
m.unionmember = IntPtr.Zero;
m.tymed = TYMED.TYMED_NULL;
m.pUnkForRelease = null;
medium = m;
}
}
public int QueryGetData(ref FORMATETC format)
{
string key = format.tymed.ToString() + format.dwAspect.ToString() + format.cfFormat.ToString();
if (base.GetDataPresent(key))
{
return 0; //S_OK
}
else
{
return 1; // S_FALSE
}
}
}
}
|
|
|
|
|
Hi,
Maybe someone can help me with my problem.
I have associated a filetype with my C# program. If I double-click on one of those, my program starts but doesn't do anything with the file because so far I didn't know what windows actually is doing.
Does windows starts the program with the filepath as a parameter or what happens?
How do I get the filepath into my program?
Thanks in advance.
|
|
|
|
|
Windows passes the filepath as a command line argument. Command line arguments are available as a string array to your applications Main method.
eg:
static class Program
{
[STAThread]
static void Main(string[] args)
{
foreach (string arg in args)
{
}
}
}
Phil
The opinions expressed in this post are not necessarily those of the author, especially if you find them impolite, inaccurate or inflammatory.
|
|
|
|
|
|
Hi,
Im using C# and MS Access,
I was wondering if someone could tell me how to store an object of a class into the database, with an sql query.
My class is variable length so i cant separate its members into columns.
i tried to do this with th ebinary formatter, but it gives an error
Type 'Billing_Module.Bill' in Assembly 'Billing Module, Version=1.0.2924.30808, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
MemoryStream fs = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, (object)newBill);
fs.Close();
aConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+path);
string queryCommand= "insert into BillHistory values ("+newBill.billNumber.ToString()+","+fs.ToString()+")";
can someone help me?
|
|
|
|
|
You need to implement ISerializable[^].
You might want to consider that if your class is changed, will it cause any problems for the saved objects.
|
|
|
|
|
Marking the classes with Serializable attribute should be enough.
|
|
|
|
|
i've had problems in the past where there are events on the object they need to be marked as nonserializable or the app tries to serialise anything that is hooked up to the event.
|
|
|
|
|