Entwickler-Ecke

Dateizugriff - unwiderrufbares Löschen von Dateien


derDoc - Mo 20.01.03 16:59
Titel: unwiderrufbares Löschen von Dateien
Hallo Leute

Ich will ein Programm schreiben, dass eine Liste von Dateien löscht. Da das Programm aber für sensible Daten gedacht ist, würde ich gern wissen, wie ich eine Datei dauerhaft löschen kann.

Ich habe mal was gelesen, man müsse den Bereich auf der Festplatte, auf dem die Datei lag mindestens 30 mal neu überschreiben, um sicher zu sein, dass man sie nicht mehr widerherstellen kann.


Woher weiß ich welche Bereiche meiner Festplatte belegt waren und wie kann ich genau diese neu beschreiben?


Delete - Mo 20.01.03 17:47

Das musst du nicht wissen. Du machst es nämlich wie folgt:


Fazit: zum einen sind alle Bytes überschrieben, u.U. mehrfach; durch das schon erwähnte "ReWrite" wird der scheinbar neuen Datei ein neuer Beginn auf der Platte zugeordnet; damit ist der alte Startpunkt verloren; und durch das Umbenennen in einen 1-Zeichen-Namen mit anschließendem Löschen zeigen Hex- und Disk-Editoren auch keine Reste des Namens mehr an, von denen man auf den ursprünglichen Inhalt schließen könnte. (Will sagen: Dateien werden in der FAT ja nur als gelöscht markiert, und wenn man im Disk-Editor einen Namen wie

Quelltext
1:
~asswort.txt                    

sieht, dann wird man neugierig.)

Ich bin nicht sicher, ob wir das Thema hier schon hatten, oder ob das noch im alten DF war. Jedenfalls sollte sich über die Suche eine funktionsfähige Routine finden lassen.
Notfalls kann ich auch mal gucken, wo ich meine Funktion habe. Aber mach dir bitte erst mal selbst einen Kopf :), das Prinzip habe ich ja beschrieben, und die Erklärungen zu den Befehlen findest du in der Hilfe.


matze - Mo 20.01.03 18:51

Folgenden Code hab ich beim EDH gefunden:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure Killdatei(Filename: string);
const bufCnt=1024;
var a: Array [1..bufCnt] of byte;
    f: file;
    i, sz: integer;
begin
  assignfile(f,FileName);
  reset(f,1);
  sz:=FileSize(f);
  for i:=1 to sz div bufCnt do blockwrite(f, a, bufCnt);
  blockwrite(f, a, sz mod bufCnt);
  closeFile(f);
  erase(f);
end;


derDoc - Mo 20.01.03 21:18

Also danke an euch beide, ich werde das mal testen und wenn noch etwas unklar ist poste ich es wieder.


Delete - Di 21.01.03 08:58

@matze: Einfach, aber dennoch funktionsfähig. Ich hätte nur eine "repeat-until"-Schleife benutzt (da spart man den Quark mit der Größenberechnung); außerdem geht´s mit einem 65k-Puffer (65.535) eindeutig schneller, und "BlockRead/BlockWrite" können max. 65k lesen und schreiben.

Na ja, das andere, was ich noch vorschlug (Dateinamen auf ein Zeichen ändern, dann noch mal mit "ReWrite" öffnen, um die Verbindung in der FAT zur alten Datenposition zu löschen), ist vielleicht Schnickschnack, lässt aber dann keine Rückschlüsse mehr auf den Namen bzw. die Position auf der Platte zu.


Dargor - Di 21.01.03 10:38

Mit BlockRead/-Write können auch Dateien größer als 65k gelesen werden.
Ich hatte mir mal mit BlockRead/-Write ein Kopierprogramm geschrieben, mit dem ich mühelos 100MB-Dateien kopieren konnte (und das sogar schneller als der COPY-Befehl von DOS *g*)

Edit: Ups, falsch gelesen. Ich nehme an, die 65k bezogen sich auf die Größe des Puffers (Array), oder?


Klabautermann - Di 21.01.03 11:10

MathiasSimmack hat folgendes geschrieben:

  • Einen Puffer, z.B.

    Quelltext
    1:
    2:
    var
      buf : array[0..65535]of byte;

    solange mit "BlockRead" einlesen, bis ein Fehler auftaucht (dann hast du das Ende erreicht)


Das ist nicht dein Ernst oder?
1. Das ende des Buffers kennst du ansonsten kannst du mit High(Buf) arbeiten.
2. Aber ich denke du meinst das ende der Datei.
Ob du dieses Ereicht hast solltest du mit EOF(f) überprüfen und nicht leichtsinnig einen Fehler provozieren.
3. Wenn du aber nur wissen willst wie groß die Datei ist, reicht ein FileSize(f) dieses liefert die Anzahl der Datensätze zurück, da du im Reset eine Datensatzgöße von einem Byte angegeben hast, entspricht dies der Dateigröße in Byte. Diesen Wert kannst du also als Endwert für deine überschreibschleife nehmen.

MathiasSimmack hat folgendes geschrieben:

  • durch die Endlosschleife (s. Punkt #3) wiederholt sich das Spiel, bis du endgültig das Ende der Datei erreicht hast; dann solltest du aufhören! :wink:

Wenn du es beendest ist es keine Endlosschleife. Generell sollte man keine Endlosschleifen in seinem Programm haben da es sich sonst Totläuft. Endlosschleifen sind ein eindeutiger Bug.


@derDoc: Ich glaube man sollte seine Dateien sogar mit bestimmten Bitmustern überschreiben. Eventuell musst du dich da noch mal schlau machen.

Gruß
Klabautermann


Delete - Di 21.01.03 12:11

@Klabautermann: Die absolut, rudimentäre Grundlage meiner Ausführung war das Kopier-Beispiel aus der Delphi-Hilfe (s. BlockRead -> F1):

Quelltext
1:
2:
3:
4:
repeat
  BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
  BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);

Ausgehend von der Grundlage lese ich einen Puffer ein und habe im letzten Parameter, o.g. "NumRead", die Anzahl der tatsächlich gelesenen Bytes. Sagen wir, die Datei ist 1.024 Bytes groß, mein Puffer aber 65k. Dann wäre der Wert beim ersten Versuch also 1.024; und da dann nichts mehr da ist, wäre er beim zweiten Versuch 0.

Vielleicht war "Endlos-Schleife" nicht der richtige Ausdruck, aber das (s. oben) habe ich gemeint. Hier nun meine Funktion, damit´s nicht wieder Unklarheiten gibt:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
function WipeFile(const szFilename: string): boolean;
var
  f      : file;
  buf    : array[0..65535]of byte;
  i,
  iRead,
  iWrite : integer;
  fpos   : longint;
begin
  {$I-}
  AssignFile(f,szFileName);
  ReSet(f,1);

  if(IoResult = 0) then begin
    repeat
      fPos := filepos(f);                    // aktuelle Position merken
      BlockRead(f,buf,sizeof(buf),iRead);    // max. 65k lesen

      // der tatsächlich gelesene Wert steckt in "iRead" und
      // ist irgendwann Null, wenn das Ende der Datei erreicht
      // wurde und keine Bytes mehr gelesen werden können
      if(iRead > 0) then
        // (alte?) Methode des DOD (US-Verteidigungsministerium):
        // einmal 00 schreiben; einmal FF schreiben (3 Wiederholungen)
        // dann F6 schreiben
        // (Norton WipeInfo macht´s heute noch so; außer, das 0x01
        // anstelle von 0xff angegeben ist)
        for i := 1 to 7 do begin
          case i of
            1,3,5 : fillchar(buf,iRead,  0); // Inhalt mit 0x00 überschreiben
            2,4,6 : fillchar(buf,iRead,255); // Inhalt mit 0xff überschreiben
            7     : fillchar(buf,iRead,246); // Inhalt mit 0xf6 überschreiben
          end;

          seek(f,fPos);                      // gespeicherte Position suchen
          BlockWrite(f,buf,iRead,iWrite);    // Puffer schreiben
          if(iWrite <> iRead) then break;    // Fehler! :o(
        end;
    until(iRead = 0) or (iWrite <> iRead);

    CloseFile(f);                            // alte Datei schließen
    Rename(f,'D');                           // alten Namen "vernichten"
    ReWrite(f,1);                            // alte Position "vernichten"
    CloseFile(f);
    Erase(f);                                // Datei löschen
  end;
  {$I+}

  Result := (IoResult = 0);
end;

Ich hab´s mir übrigens einfach gemacht und nicht lange rumgerechnet. Deswegen die FOR-Schleife in der Form, wie sie da drin steht.