Subversion Repositories indexer_suite

Rev

Rev 6 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6 Rev 8
1
unit IndexCreatorForm;
1
unit IndexCreatorForm;
2
 
2
 
3
// TODO: vor einem fehler bitte vorher einen löschvorgang durchführen --> geht nicht?
3
// TODO: vor einem fehler bitte vorher einen löschvorgang durchführen --> geht nicht?
4
// TODO: berücksichtigen, wenn datei gesperrt. etc, fehler anschauen
4
// TODO: berücksichtigen, wenn datei gesperrt. etc, fehler anschauen
5
// TODO: warum sind in der db mehr einträge als dateien auf der festplatte sind?!
5
// TODO: warum sind in der db mehr einträge als dateien auf der festplatte sind?!
6
// TODO: Möglichkeit geben, Dateien und Verzeichnisse auszuschließen
6
// TODO: Möglichkeit geben, Dateien und Verzeichnisse auszuschließen
7
// TODO: should we include flags (readonly, invisible, compressed, encrypted)?
7
// TODO: should we include flags (readonly, invisible, compressed, encrypted)?
8
// TODO: search+replace tool, wenn man große verschiebungen vorgenommen hat
8
// TODO: search+replace tool, wenn man große verschiebungen vorgenommen hat
9
// update top (100000) files set filename = replace(filename, '\\?\Volume{560e8251-2b6a-4ab7-82fc-d03df4d93538}\', 'EHDD:\') where filename like '%\\?\%';
9
// update top (100000) files set filename = replace(filename, '\\?\Volume{560e8251-2b6a-4ab7-82fc-d03df4d93538}\', 'EHDD:\') where filename like '%\\?\%';
10
// TODO: anzeige, wie viele stunden der prozess schon läuft
10
// TODO: anzeige, wie viele stunden der prozess schon läuft
11
// TODO: multithreading
11
// TODO: multithreading
12
// TODO: diverse tools schreiben, die die datenbank nutzen, z.b. ein tool, das prüft, ob ein verzeichnis vollständig redundant ist
12
// TODO: diverse tools schreiben, die die datenbank nutzen, z.b. ein tool, das prüft, ob ein verzeichnis vollständig redundant ist
13
// TODO: Beim Lauf F:\nas\data wurden 1312 Fehler gefunden, aber nicht geloggt! ?! Eine exception im exception handler?!
13
// TODO: Beim Lauf F:\nas\data wurden 1312 Fehler gefunden, aber nicht geloggt! ?! Eine exception im exception handler?!
14
// => nochmal durchlaufen lassen
14
// => nochmal durchlaufen lassen
15
// TODO: "Laufwerk" EHDD: soll man auch eingeben dürfen (das ist z.b. wichtig, wenn man Querverknüpfung vom Explorer verwendet)
15
// TODO: "Laufwerk" EHDD: soll man auch eingeben dürfen (das ist z.b. wichtig, wenn man Querverknüpfung vom Explorer verwendet)
16
// TODO: validate modus auch ohne prüfsummencheck. nur gucken ob die dateien existieren
16
// TODO: validate modus auch ohne prüfsummencheck. nur gucken ob die dateien existieren
17
 
17
 
18
{$DEFINE VIATHINKSOFT}
18
{$DEFINE VIATHINKSOFT}
19
 
19
 
20
interface
20
interface
21
 
21
 
22
uses
22
uses
23
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
23
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
24
  Dialogs, StdCtrls, ComCtrls, ExtCtrls, DB, ADODB, Menus;
24
  Dialogs, StdCtrls, ComCtrls, ExtCtrls, DB, ADODB, Menus;
25
 
25
 
26
const
26
const
27
  modusUpdate = 0;
27
  modusUpdate = 0;
28
  modusRecreate = 1;
28
  modusRecreate = 1;
29
  modusValidation = 2;
29
  modusValidation = 2;
30
 
30
 
31
type
31
type
32
  TfrmIndexCreator = class(TForm)
32
  TfrmIndexCreator = class(TForm)
33
    Button1: TButton;
33
    Button1: TButton;
34
    Label1: TLabel;
34
    Label1: TLabel;
35
    LabeledEdit2: TLabeledEdit;
35
    LabeledEdit2: TLabeledEdit;
36
    Button2: TButton;
36
    Button2: TButton;
37
    Label2: TLabel;
37
    Label2: TLabel;
38
    Label3: TLabel;
38
    Label3: TLabel;
39
    Label4: TLabel;
39
    Label4: TLabel;
40
    Label5: TLabel;
40
    Label5: TLabel;
41
    Label6: TLabel;
41
    Label6: TLabel;
42
    Label7: TLabel;
42
    Label7: TLabel;
43
    PopupMenu1: TPopupMenu;
43
    PopupMenu1: TPopupMenu;
44
    Copyuniquepathtoclipboard1: TMenuItem;
44
    Copyuniquepathtoclipboard1: TMenuItem;
45
    Label8: TLabel;
45
    Label8: TLabel;
46
    Label9: TLabel;
46
    Label9: TLabel;
47
    Label10: TLabel;
47
    Label10: TLabel;
48
    Label11: TLabel;
48
    Label11: TLabel;
49
    Label12: TLabel;
49
    Label12: TLabel;
50
    Label13: TLabel;
50
    Label13: TLabel;
51
    Memo1: TMemo;
51
    Memo1: TMemo;
52
    Button4: TButton;
52
    Button4: TButton;
53
    Label14: TLabel;
53
    Label14: TLabel;
54
    cbNoDelete: TCheckBox;
54
    cbNoDelete: TCheckBox;
55
    Memo2: TMemo;
55
    Memo2: TMemo;
56
    cbVerboseLogs: TCheckBox;
56
    cbVerboseLogs: TCheckBox;
57
    cbSimulate: TCheckBox;
57
    cbSimulate: TCheckBox;
58
    rgModus: TRadioGroup;
58
    rgModus: TRadioGroup;
59
    procedure Button1Click(Sender: TObject);
59
    procedure Button1Click(Sender: TObject);
60
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
60
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
61
    procedure Button2Click(Sender: TObject);
61
    procedure Button2Click(Sender: TObject);
62
    procedure FormShow(Sender: TObject);
62
    procedure FormShow(Sender: TObject);
63
    procedure Copyuniquepathtoclipboard1Click(Sender: TObject);
63
    procedure Copyuniquepathtoclipboard1Click(Sender: TObject);
64
    procedure Button4Click(Sender: TObject);
64
    procedure Button4Click(Sender: TObject);
65
    procedure rgModusClick(Sender: TObject);
65
    procedure rgModusClick(Sender: TObject);
66
  private
66
  private
67
    StopRequest: boolean;
67
    StopRequest: boolean;
68
    sumsize: int64;
68
    sumsize: int64;
69
    sumfiles: int64;
69
    sumfiles: int64;
70
    sumfiles_new: int64;
70
    sumfiles_new: int64;
71
    sumfiles_updated: int64;
71
    sumfiles_updated: int64;
72
    sumfiles_error: int64;
72
    sumfiles_error: int64;
73
    sumfiles_deleted: int64;
73
    sumfiles_deleted: int64;
74
    sumfiles_integrityfail: int64;
74
    sumfiles_integrityfail: int64;
75
    function TableName: string;
75
    function TableName: string;
76
    function conn: TAdoConnection;
76
    function conn: TAdoConnection;
77
    procedure Rec(StartDir: string; const FileMask: string);
77
    procedure Rec(StartDir: string; const FileMask: string);
78
    procedure CheckFile(const originalFileName, uniqueFilename: string);
78
    procedure CheckFile(const originalFileName, uniqueFilename: string);
79
    procedure EnableDisableControls(enabled: boolean);
79
    procedure EnableDisableControls(enabled: boolean);
80
    procedure IndexDrive(initialdir: string);
80
    procedure IndexDrive(initialdir: string);
81
    procedure RedrawStats;
81
    procedure RedrawStats;
82
    procedure DeleteVanishedFiles(mask: string = '');
82
    procedure DeleteVanishedFiles(mask: string = '');
83
    class function DriveGuid(const Letter: char): string; static;
83
    class function DriveGuid(const Letter: char): string; static;
84
    class function uniqueFilename(const filename: string): string; static;
84
    class function uniqueFilename(const filename: string): string; static;
85
    class function VtsSpecial(const filename: string): string; static;
85
    class function VtsSpecial(const filename: string): string; static;
86
    procedure DeleteAllFiles(mask: string = '');
86
    procedure DeleteAllFiles(mask: string = '');
87
  end;
87
  end;
88
 
88
 
89
implementation
89
implementation
90
 
90
 
91
{$R *.dfm}
91
{$R *.dfm}
92
 
92
 
93
uses
93
uses
94
  FileCtrl, DateUtils, inifiles, IdHashMessageDigest, idHash, Math, Clipbrd,
94
  FileCtrl, DateUtils, inifiles, IdHashMessageDigest, idHash, Math, Clipbrd,
95
  StrUtils, AdoConnHelper, MainForm;
95
  StrUtils, AdoConnHelper, MainForm;
96
 
96
 
97
const
97
const
98
  Win32ImportSuffix = {$IFDEF Unicode}'W'{$ELSE}'A'{$ENDIF};
98
  Win32ImportSuffix = {$IFDEF Unicode}'W'{$ELSE}'A'{$ENDIF};
99
 
99
 
100
function GetVolumeNameForVolumeMountPointA(lpszVolumeMountPoint: PAnsiChar;
100
function GetVolumeNameForVolumeMountPointA(lpszVolumeMountPoint: PAnsiChar;
101
  lpszVolumeName: PAnsiChar; cchBufferLength: DWORD): BOOL; stdcall;
101
  lpszVolumeName: PAnsiChar; cchBufferLength: DWORD): BOOL; stdcall;
102
  external 'kernel32.dll';
102
  external 'kernel32.dll';
103
function GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint: PWideChar;
103
function GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint: PWideChar;
104
  lpszVolumeName: PWideChar; cchBufferLength: DWORD): BOOL; stdcall;
104
  lpszVolumeName: PWideChar; cchBufferLength: DWORD): BOOL; stdcall;
105
  external 'kernel32.dll';
105
  external 'kernel32.dll';
106
function GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint: PChar;
106
function GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint: PChar;
107
  lpszVolumeName: PChar; cchBufferLength: DWORD): BOOL; stdcall;
107
  lpszVolumeName: PChar; cchBufferLength: DWORD): BOOL; stdcall;
108
  external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPoint' +
108
  external 'kernel32.dll' name 'GetVolumeNameForVolumeMountPoint' +
109
  Win32ImportSuffix;
109
  Win32ImportSuffix;
110
 
110
 
111
const
111
const
112
  ERROR_FIELD_SIZE = 200;
112
  ERROR_FIELD_SIZE = 200;
113
{$IFDEF VIATHINKSOFT}
113
{$IFDEF VIATHINKSOFT}
-
 
114
  // Example of multiple drives merging to one Index
-
 
115
  // Find out via "mountvol" command
114
  GUID_EHDD_A = '\\?\Volume{31e044b1-28dc-11e6-9bae-d067e54bf736}\';
116
  GUID_EHDD_A = '\\?\Volume{31e044b1-28dc-11e6-9bae-d067e54bf736}\';
115
  GUID_EHDD_B = '\\?\Volume{560e8251-2b6a-4ab7-82fc-d03df4d93538}\';
117
  GUID_EHDD_B = '\\?\Volume{560e8251-2b6a-4ab7-82fc-d03df4d93538}\';
-
 
118
  GUID_EHDD_R = '\\?\Volume{9d53ea3c-175c-4a8f-a7b4-7b9e6b765e58}\';
116
{$ENDIF}
119
{$ENDIF}
117
 
120
 
118
function MD5File(const filename: string): string;
121
function MD5File(const filename: string): string;
119
var
122
var
120
  IdMD5: TIdHashMessageDigest5;
123
  IdMD5: TIdHashMessageDigest5;
121
  FS: TFileStream;
124
  FS: TFileStream;
122
begin
125
begin
123
  IdMD5 := TIdHashMessageDigest5.Create;
126
  IdMD5 := TIdHashMessageDigest5.Create;
124
  FS := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
127
  FS := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
125
  try
128
  try
126
{$IFDEF UNICODE} // I actually do not know at which version of Delphi/Indy, this has changed.
129
{$IFDEF UNICODE} // I actually do not know at which version of Delphi/Indy, this has changed.
127
    Result := IdMD5.HashStreamAsHex(FS);
130
    Result := IdMD5.HashStreamAsHex(FS);
128
{$ELSE}
131
{$ELSE}
129
    Result := IdMD5.AsHex(IdMD5.HashValue(FS));
132
    Result := IdMD5.AsHex(IdMD5.HashValue(FS));
130
{$ENDIF}
133
{$ENDIF}
131
  finally
134
  finally
132
    FS.Free;
135
    FS.Free;
133
    IdMD5.Free;
136
    IdMD5.Free;
134
  end;
137
  end;
135
end;
138
end;
136
 
139
 
137
function FileMTime_UTC(const filename: string): TDateTime;
140
function FileMTime_UTC(const filename: string): TDateTime;
138
var
141
var
139
  fad: TWin32FileAttributeData;
142
  fad: TWin32FileAttributeData;
140
  systime: SYSTEMTIME;
143
  systime: SYSTEMTIME;
141
begin
144
begin
142
  if not GetFileAttributesEx(PChar(filename), GetFileExInfoStandard, @fad) then
145
  if not GetFileAttributesEx(PChar(filename), GetFileExInfoStandard, @fad) then
143
    RaiseLastOSError;
146
    RaiseLastOSError;
144
 
147
 
145
  FileTimeToSystemTime(fad.ftLastWriteTime, systime);
148
  FileTimeToSystemTime(fad.ftLastWriteTime, systime);
146
 
149
 
147
  Result := SystemTimeToDateTime(systime);
150
  Result := SystemTimeToDateTime(systime);
148
end;
151
end;
149
 
152
 
150
function FileCTime_UTC(const filename: string): TDateTime;
153
function FileCTime_UTC(const filename: string): TDateTime;
151
var
154
var
152
  fad: TWin32FileAttributeData;
155
  fad: TWin32FileAttributeData;
153
  systime: SYSTEMTIME;
156
  systime: SYSTEMTIME;
154
begin
157
begin
155
  if not GetFileAttributesEx(PChar(filename), GetFileExInfoStandard, @fad) then
158
  if not GetFileAttributesEx(PChar(filename), GetFileExInfoStandard, @fad) then
156
    RaiseLastOSError;
159
    RaiseLastOSError;
157
 
160
 
158
  FileTimeToSystemTime(fad.ftCreationTime, systime);
161
  FileTimeToSystemTime(fad.ftCreationTime, systime);
159
 
162
 
160
  Result := SystemTimeToDateTime(systime);
163
  Result := SystemTimeToDateTime(systime);
161
end;
164
end;
162
 
165
 
163
function GetFileSize(const AFileName: String): int64;
166
function GetFileSize(const AFileName: String): int64;
164
var
167
var
165
  lFindData: TWin32FindData;
168
  lFindData: TWin32FindData;
166
  lHandle: Cardinal;
169
  lHandle: Cardinal;
167
begin
170
begin
168
  // https://www.delphipraxis.net/24331-dateigroesse-einer-beliebigen-datei-ermitteln.html
171
  // https://www.delphipraxis.net/24331-dateigroesse-einer-beliebigen-datei-ermitteln.html
169
  lHandle := FindFirstFile(PChar(AFileName), lFindData);
172
  lHandle := FindFirstFile(PChar(AFileName), lFindData);
170
  if (lHandle <> INVALID_HANDLE_VALUE) then
173
  if (lHandle <> INVALID_HANDLE_VALUE) then
171
  begin
174
  begin
172
    Result := lFindData.nFileSizeLow;
175
    Result := lFindData.nFileSizeLow;
173
    PCardinal(Cardinal(@Result) + SizeOf(Cardinal))^ := lFindData.nFileSizeHigh;
176
    PCardinal(Cardinal(@Result) + SizeOf(Cardinal))^ := lFindData.nFileSizeHigh;
174
    Windows.FindClose(lHandle);
177
    Windows.FindClose(lHandle);
175
  end
178
  end
176
  else
179
  else
177
    Result := 0;
180
    Result := 0;
178
end;
181
end;
179
 
182
 
180
function IntToStr2(i: int64): string;
183
function IntToStr2(i: int64): string;
181
begin
184
begin
182
  // https://www.delphipraxis.net/150464-integer-mit-tausender-trennzeichen-ausgeben.html
185
  // https://www.delphipraxis.net/150464-integer-mit-tausender-trennzeichen-ausgeben.html
183
  Result := Format('%.0n', [i / 1]);
186
  Result := Format('%.0n', [i / 1]);
184
end;
187
end;
185
 
188
 
186
function ConvertBytes(Bytes: int64): string;
189
function ConvertBytes(Bytes: int64): string;
187
const
190
const
188
  Description: Array [0 .. 8] of string = ('Bytes', 'KB', 'MB', 'GB', 'TB',
191
  Description: Array [0 .. 8] of string = ('Bytes', 'KB', 'MB', 'GB', 'TB',
189
    'PB', 'EB', 'ZB', 'YB');
192
    'PB', 'EB', 'ZB', 'YB');
190
var
193
var
191
  i: Integer;
194
  i: Integer;
192
begin
195
begin
193
  // https://stackoverflow.com/questions/30548940/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-delphi
196
  // https://stackoverflow.com/questions/30548940/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-delphi
194
  i := 0;
197
  i := 0;
195
 
198
 
196
  while Bytes > Power(1024, i + 1) do
199
  while Bytes > Power(1024, i + 1) do
197
    Inc(i);
200
    Inc(i);
198
 
201
 
199
  Result := FormatFloat('###0.##', Bytes / IntPower(1024, i)) + ' ' +
202
  Result := FormatFloat('###0.##', Bytes / IntPower(1024, i)) + ' ' +
200
    Description[i];
203
    Description[i];
201
end;
204
end;
202
 
205
 
203
var
206
var
204
  DriveGuidCache: TStringList = nil;
207
  DriveGuidCache: TStringList = nil;
205
 
208
 
206
class function TfrmIndexCreator.DriveGuid(const Letter: char): string;
209
class function TfrmIndexCreator.DriveGuid(const Letter: char): string;
207
var
210
var
208
  Buffer: array [0 .. 49] of char;
211
  Buffer: array [0 .. 49] of char;
209
begin
212
begin
210
  if not Assigned(DriveGuidCache) then
213
  if not Assigned(DriveGuidCache) then
211
    DriveGuidCache := TStringList.Create;
214
    DriveGuidCache := TStringList.Create;
212
 
215
 
213
  Result := DriveGuidCache.Values[Letter];
216
  Result := DriveGuidCache.Values[Letter];
214
  if Result = '' then
217
  if Result = '' then
215
  begin
218
  begin
216
    Win32Check(GetVolumeNameForVolumeMountPoint(PChar(Letter + ':\'), Buffer,
219
    Win32Check(GetVolumeNameForVolumeMountPoint(PChar(Letter + ':\'), Buffer,
217
      Length(Buffer)));
220
      Length(Buffer)));
218
    Result := Buffer;
221
    Result := Buffer;
219
    DriveGuidCache.Values[Letter] := Result;
222
    DriveGuidCache.Values[Letter] := Result;
220
  end;
223
  end;
221
end;
224
end;
222
 
225
 
223
class function TfrmIndexCreator.uniqueFilename(const filename: string): string;
226
class function TfrmIndexCreator.uniqueFilename(const filename: string): string;
224
var
227
var
225
  guid: string;
228
  guid: string;
226
begin
229
begin
227
  if Length(filename) < 2 then
230
  if Length(filename) < 2 then
228
    exit;
231
    exit;
229
  if filename[2] = ':' then
232
  if filename[2] = ':' then
230
  begin
233
  begin
231
    guid := DriveGuid(filename[1]);
234
    guid := DriveGuid(filename[1]);
232
 
235
 
233
    Result := guid + Copy(filename, 4, Length(filename) - 3);
236
    Result := guid + Copy(filename, 4, Length(filename) - 3);
234
 
237
 
235
    // result := LowerCase(result);
238
    // result := LowerCase(result);
236
  end
239
  end
237
  else
240
  else
238
    Result := filename; // z.B. UNC-Pfad
241
    Result := filename; // z.B. UNC-Pfad
239
end;
242
end;
240
 
243
 
241
class function TfrmIndexCreator.VtsSpecial(const filename: string): string;
244
class function TfrmIndexCreator.VtsSpecial(const filename: string): string;
242
begin
245
begin
243
  Result := filename;
246
  Result := filename;
244
{$IFDEF VIATHINKSOFT}
247
{$IFDEF VIATHINKSOFT}
245
  Result := StringReplace(Result, GUID_EHDD_A, 'EHDD:\', []);
248
  Result := StringReplace(Result, GUID_EHDD_A, 'EHDD:\', []);
246
  Result := StringReplace(Result, GUID_EHDD_B, 'EHDD:\', []);
249
  Result := StringReplace(Result, GUID_EHDD_B, 'EHDD:\', []);
-
 
250
  Result := StringReplace(Result, GUID_EHDD_R, 'EHDD:\', []);
247
{$ENDIF}
251
{$ENDIF}
248
end;
252
end;
249
 
253
 
250
function SpecialCompare(a, b: TDateTime): boolean; // true = same timestamp
254
function SpecialCompare(a, b: TDateTime): boolean; // true = same timestamp
251
begin
255
begin
252
  if SecondsBetween(a,b) < 2 then exit(true); // equal
256
  if SecondsBetween(a,b) < 2 then exit(true); // equal
253
 
257
 
254
  if SecondsBetween(a,b) > 7200 then exit(false);
258
  if SecondsBetween(a,b) > 7200 then exit(false);
255
 
259
 
256
  // Minute and Second equal, and difference is < 2h: fair enough, seems to be a DST issue
260
  // Minute and Second equal, and difference is < 2h: fair enough, seems to be a DST issue
257
  if copy(TimeToStr(a),4,5) = copy(TimeToStr(b),4,5) then exit(true);
261
  if copy(TimeToStr(a),4,5) = copy(TimeToStr(b),4,5) then exit(true);
258
 
262
 
259
  result := false;
263
  result := false;
260
end;
264
end;
261
 
265
 
262
procedure TfrmIndexCreator.CheckFile(const originalFileName,
266
procedure TfrmIndexCreator.CheckFile(const originalFileName,
263
  uniqueFilename: string);
267
  uniqueFilename: string);
264
 
268
 
265
  function DateTimeToSQL(dt: TDateTime): string;
269
  function DateTimeToSQL(dt: TDateTime): string;
266
  begin
270
  begin
267
    if dt = -1 then
271
    if dt = -1 then
268
      Result := 'NULL'
272
      Result := 'NULL'
269
    else
273
    else
270
      Result := conn.SQLStringEscape(DateTimetoStr(dt));
274
      Result := conn.SQLStringEscape(DateTimetoStr(dt));
271
  end;
275
  end;
272
 
276
 
273
type
277
type
274
  TExistResult = (erDoesNotExist, erHadError, erChanged, erUnchanged);
278
  TExistResult = (erDoesNotExist, erHadError, erChanged, erUnchanged);
275
 
279
 
276
var
280
var
277
  lastCheckedMd5: string;
281
  lastCheckedMd5: string;
278
 
282
 
279
  function Exists(const filename: string; size: int64;
283
  function Exists(const filename: string; size: int64;
280
    const modified: TDateTime): TExistResult;
284
    const modified: TDateTime): TExistResult;
281
  var
285
  var
282
    q: TADODataSet;
286
    q: TADODataSet;
283
  begin
287
  begin
284
    q := conn.GetTable('select error, size, modified, md5hash from ' + TableName
288
    q := conn.GetTable('select error, size, modified, md5hash from ' + TableName
285
      + ' where filename = ' + conn.SQLStringEscape
289
      + ' where filename = ' + conn.SQLStringEscape
286
      (VtsSpecial(uniqueFilename)));
290
      (VtsSpecial(uniqueFilename)));
287
    try
291
    try
288
      if q.RecordCount = 0 then
292
      if q.RecordCount = 0 then
289
        Result := erDoesNotExist
293
        Result := erDoesNotExist
290
      else if not q.Fields[0].IsNull then
294
      else if not q.Fields[0].IsNull then
291
        Result := erHadError
295
        Result := erHadError
292
      else if (q.Fields[1].AsString <> IntToStr(size)) or // we are combining strings because of int64
296
      else if (q.Fields[1].AsString <> IntToStr(size)) or // we are combining strings because of int64
293
        not SpecialCompare(q.Fields[2].AsDateTime, modified) then
297
        not SpecialCompare(q.Fields[2].AsDateTime, modified) then
294
      begin
298
      begin
295
        Result := erChanged
299
        Result := erChanged
296
      end
300
      end
297
      else
301
      else
298
        Result := erUnchanged;
302
        Result := erUnchanged;
299
      lastCheckedMd5 := q.Fields[3].AsString;
303
      lastCheckedMd5 := q.Fields[3].AsString;
300
    finally
304
    finally
301
      FreeAndNil(q);
305
      FreeAndNil(q);
302
    end;
306
    end;
303
  end;
307
  end;
304
 
308
 
305
var
309
var
306
  created, modified: TDateTime;
310
  created, modified: TDateTime;
307
  size: int64;
311
  size: int64;
308
  md5: string;
312
  md5: string;
309
begin
313
begin
310
  Label1.Caption := MinimizeName(originalFileName, Label1.Canvas, Label1.Width);
314
  Label1.Caption := MinimizeName(originalFileName, Label1.Canvas, Label1.Width);
311
  Application.ProcessMessages;
315
  Application.ProcessMessages;
312
 
316
 
313
  try
317
  try
314
    if FileExists(uniqueFilename) then
318
    if FileExists(uniqueFilename) then
315
      created := FileCTime_UTC(uniqueFilename)
319
      created := FileCTime_UTC(uniqueFilename)
316
    else
320
    else
317
      created := -1;
321
      created := -1;
318
 
322
 
319
    if FileExists(uniqueFilename) then
323
    if FileExists(uniqueFilename) then
320
      modified := FileMTime_UTC(uniqueFilename)
324
      modified := FileMTime_UTC(uniqueFilename)
321
    else
325
    else
322
      modified := -1;
326
      modified := -1;
323
 
327
 
324
    size := GetFileSize(uniqueFilename);
328
    size := GetFileSize(uniqueFilename);
325
    Inc(sumsize, size);
329
    Inc(sumsize, size);
326
    Inc(sumfiles);
330
    Inc(sumfiles);
327
 
331
 
328
    if rgModus.ItemIndex = modusRecreate then
332
    if rgModus.ItemIndex = modusRecreate then
329
    begin
333
    begin
330
      md5 := MD5File(uniqueFilename);
334
      md5 := MD5File(uniqueFilename);
331
      if not cbSimulate.Checked then
335
      if not cbSimulate.Checked then
332
      begin
336
      begin
333
        conn.ExecSQL('INSERT INTO ' + TableName +
337
        conn.ExecSQL('INSERT INTO ' + TableName +
334
          ' (filename, size, created, modified, md5hash, error) values (' +
338
          ' (filename, size, created, modified, md5hash, error) values (' +
335
          conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ', ' +
339
          conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ', ' +
336
          IntToStr(size) + ', ' + DateTimeToSQL(created) +
340
          IntToStr(size) + ', ' + DateTimeToSQL(created) +
337
          ', ' + DateTimeToSQL(modified) + ', ' +
341
          ', ' + DateTimeToSQL(modified) + ', ' +
338
          conn.SQLStringEscape(LowerCase(md5)) + ', NULL);');
342
          conn.SQLStringEscape(LowerCase(md5)) + ', NULL);');
339
      end;
343
      end;
340
      if cbVerboseLogs.Checked then
344
      if cbVerboseLogs.Checked then
341
        Memo2.Lines.Add('New: ' + uniqueFilename);
345
        Memo2.Lines.Add('New: ' + uniqueFilename);
342
      Inc(sumfiles_new);
346
      Inc(sumfiles_new);
343
    end
347
    end
344
    else
348
    else
345
    begin
349
    begin
346
      case Exists(uniqueFilename, size, modified) of
350
      case Exists(uniqueFilename, size, modified) of
347
        erDoesNotExist: // File does not exist or has a different hash
351
        erDoesNotExist: // File does not exist or has a different hash
348
          begin
352
          begin
349
            if rgModus.ItemIndex <> modusValidation then
353
            if rgModus.ItemIndex <> modusValidation then
350
              md5 := MD5File(uniqueFilename);
354
              md5 := MD5File(uniqueFilename);
351
            if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
355
            if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
352
            then
356
            then
353
            begin
357
            begin
354
              conn.ExecSQL('INSERT INTO ' + TableName +
358
              conn.ExecSQL('INSERT INTO ' + TableName +
355
                ' (filename, size, created, modified, md5hash, error) values ('
359
                ' (filename, size, created, modified, md5hash, error) values ('
356
                + conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ', ' +
360
                + conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ', ' +
357
                IntToStr(size) + ', ' +
361
                IntToStr(size) + ', ' +
358
                DateTimeToSQL(created) + ', ' +
362
                DateTimeToSQL(created) + ', ' +
359
                DateTimeToSQL(modified) + ', ' +
363
                DateTimeToSQL(modified) + ', ' +
360
                conn.SQLStringEscape(LowerCase(md5)) + ', NULL);');
364
                conn.SQLStringEscape(LowerCase(md5)) + ', NULL);');
361
            end;
365
            end;
362
            if cbVerboseLogs.Checked then
366
            if cbVerboseLogs.Checked then
363
              Memo2.Lines.Add('New: ' + uniqueFilename);
367
              Memo2.Lines.Add('New: ' + uniqueFilename);
364
            Inc(sumfiles_new);
368
            Inc(sumfiles_new);
365
          end;
369
          end;
366
        erHadError, erChanged:
370
        erHadError, erChanged:
367
          begin
371
          begin
368
            if rgModus.ItemIndex <> modusValidation then
372
            if rgModus.ItemIndex <> modusValidation then
369
              md5 := MD5File(uniqueFilename);
373
              md5 := MD5File(uniqueFilename);
370
            if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
374
            if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
371
            then
375
            then
372
            begin
376
            begin
373
              conn.ExecSQL('UPDATE ' + TableName + ' SET size = ' +
377
              conn.ExecSQL('UPDATE ' + TableName + ' SET size = ' +
374
                IntToStr(size) + ', created = ' +
378
                IntToStr(size) + ', created = ' +
375
                DateTimeToSQL(created) + ', modified = ' +
379
                DateTimeToSQL(created) + ', modified = ' +
376
                DateTimeToSQL(modified) + ', md5hash = ' +
380
                DateTimeToSQL(modified) + ', md5hash = ' +
377
                conn.SQLStringEscape(LowerCase(md5)) +
381
                conn.SQLStringEscape(LowerCase(md5)) +
378
                ', error = NULL WHERE filename = ' + conn.SQLStringEscape
382
                ', error = NULL WHERE filename = ' + conn.SQLStringEscape
379
                (VtsSpecial(uniqueFilename)) + ';');
383
                (VtsSpecial(uniqueFilename)) + ';');
380
            end;
384
            end;
381
            if cbVerboseLogs.Checked then
385
            if cbVerboseLogs.Checked then
382
              Memo2.Lines.Add('Updated: ' + uniqueFilename);
386
              Memo2.Lines.Add('Updated: ' + uniqueFilename);
383
            Inc(sumfiles_updated);
387
            Inc(sumfiles_updated);
384
          end;
388
          end;
385
        erUnchanged: // Date/Time+Size has not changed
389
        erUnchanged: // Date/Time+Size has not changed
386
          begin
390
          begin
387
            {$REGION 'Update it to correct wrong UTC/DST datasets...'}
391
            {$REGION 'Update it to correct wrong UTC/DST datasets...'}
388
            conn.ExecSQL('UPDATE ' + TableName + ' SET size = ' +
392
            conn.ExecSQL('UPDATE ' + TableName + ' SET size = ' +
389
              IntToStr(size) + ', created = ' +
393
              IntToStr(size) + ', created = ' +
390
              DateTimeToSQL(created) + ', modified = ' +
394
              DateTimeToSQL(created) + ', modified = ' +
391
              DateTimeToSQL(modified) +
395
              DateTimeToSQL(modified) +
392
              ', error = NULL WHERE filename = ' + conn.SQLStringEscape
396
              ', error = NULL WHERE filename = ' + conn.SQLStringEscape
393
              (VtsSpecial(uniqueFilename)) + ';');
397
              (VtsSpecial(uniqueFilename)) + ';');
394
            {$ENDREGION}
398
            {$ENDREGION}
395
 
399
 
396
            if rgModus.ItemIndex = modusValidation then
400
            if rgModus.ItemIndex = modusValidation then
397
            begin
401
            begin
398
              md5 := MD5File(uniqueFilename);
402
              md5 := MD5File(uniqueFilename);
399
              if not SameText(md5, lastCheckedMd5) then
403
              if not SameText(md5, lastCheckedMd5) then
400
              begin
404
              begin
401
                Memo2.Lines.Add
405
                Memo2.Lines.Add
402
                  ('!!! HASH HAS CHANGED WHILE DATETIME+SIZE IS THE SAME: ' +
406
                  ('!!! HASH HAS CHANGED WHILE DATETIME+SIZE IS THE SAME: ' +
403
                  uniqueFilename + ' (' + lastCheckedMd5 + ' became ' +
407
                  uniqueFilename + ' (' + lastCheckedMd5 + ' became ' +
404
                  md5 + ')');
408
                  md5 + ')');
405
                Memo2.Color := clRed;
409
                Memo2.Color := clRed;
406
                Inc(sumfiles_integrityfail);
410
                Inc(sumfiles_integrityfail);
407
              end;
411
              end;
408
            end;
412
            end;
409
          end;
413
          end;
410
      end;
414
      end;
411
    end;
415
    end;
412
  except
416
  except
413
    on E: Exception do
417
    on E: Exception do
414
    begin
418
    begin
415
      if E is EAbort then
419
      if E is EAbort then
416
        Abort;
420
        Abort;
417
      // if AdoConnection1.InTransaction then AdoConnection1.RollbackTrans;
421
      // if AdoConnection1.InTransaction then AdoConnection1.RollbackTrans;
418
      // AdoConnection1.BeginTrans;
422
      // AdoConnection1.BeginTrans;
419
      try
423
      try
420
        if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
424
        if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
421
        then
425
        then
422
        begin
426
        begin
423
          conn.ExecSQL('DELETE FROM ' + TableName + ' WHERE filename = ' +
427
          conn.ExecSQL('DELETE FROM ' + TableName + ' WHERE filename = ' +
424
            conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ';');
428
            conn.SQLStringEscape(VtsSpecial(uniqueFilename)) + ';');
425
          conn.ExecSQL('INSERT INTO ' + TableName +
429
          conn.ExecSQL('INSERT INTO ' + TableName +
426
            ' (filename, size, created, modified, md5hash, error) values (' +
430
            ' (filename, size, created, modified, md5hash, error) values (' +
427
            conn.SQLStringEscape(VtsSpecial(uniqueFilename)) +
431
            conn.SQLStringEscape(VtsSpecial(uniqueFilename)) +
428
            ', NULL, NULL, NULL, NULL, ' + conn.SQLStringEscape(Copy(E.Message,
432
            ', NULL, NULL, NULL, NULL, ' + conn.SQLStringEscape(Copy(E.Message,
429
            1, ERROR_FIELD_SIZE)) + ');');
433
            1, ERROR_FIELD_SIZE)) + ');');
430
          Memo2.Lines.Add('Error (logged): ' + E.Message + ' at file ' +
434
          Memo2.Lines.Add('Error (logged): ' + E.Message + ' at file ' +
431
            VtsSpecial(uniqueFilename));
435
            VtsSpecial(uniqueFilename));
432
        end
436
        end
433
        else
437
        else
434
        begin
438
        begin
435
          Memo2.Lines.Add('Error: ' + E.Message + ' at file ' +
439
          Memo2.Lines.Add('Error: ' + E.Message + ' at file ' +
436
            VtsSpecial(uniqueFilename));
440
            VtsSpecial(uniqueFilename));
437
        end;
441
        end;
438
        // AdoConnection1.CommitTrans;
442
        // AdoConnection1.CommitTrans;
439
      except
443
      except
440
        // AdoConnection1.RollbackTrans;
444
        // AdoConnection1.RollbackTrans;
441
        Memo2.Lines.Add('Cannot write error into file database! ' + E.Message +
445
        Memo2.Lines.Add('Cannot write error into file database! ' + E.Message +
442
          ' at file ' + VtsSpecial(uniqueFilename));
446
          ' at file ' + VtsSpecial(uniqueFilename));
443
      end;
447
      end;
444
      Inc(sumfiles_error);
448
      Inc(sumfiles_error);
445
    end;
449
    end;
446
  end;
450
  end;
447
 
451
 
448
  RedrawStats;
452
  RedrawStats;
449
  Application.ProcessMessages;
453
  Application.ProcessMessages;
450
end;
454
end;
451
 
455
 
452
function TfrmIndexCreator.conn: TAdoConnection;
456
function TfrmIndexCreator.conn: TAdoConnection;
453
begin
457
begin
454
  Result := frmMain.AdoConnection1;
458
  Result := frmMain.AdoConnection1;
455
end;
459
end;
456
 
460
 
457
procedure TfrmIndexCreator.RedrawStats;
461
procedure TfrmIndexCreator.RedrawStats;
458
begin
462
begin
459
  Label5.Caption := ConvertBytes(sumsize);
463
  Label5.Caption := ConvertBytes(sumsize);
460
  Label6.Caption := IntToStr2(sumfiles);
464
  Label6.Caption := IntToStr2(sumfiles);
461
  Label7.Caption := IntToStr2(sumfiles_new);
465
  Label7.Caption := IntToStr2(sumfiles_new);
462
  Label9.Caption := IntToStr2(sumfiles_updated);
466
  Label9.Caption := IntToStr2(sumfiles_updated);
463
  Label11.Caption := IntToStr2(sumfiles_error);
467
  Label11.Caption := IntToStr2(sumfiles_error);
464
  Label12.Caption := IntToStr2(sumfiles_deleted);
468
  Label12.Caption := IntToStr2(sumfiles_deleted);
465
  // LabelXX.Caption := IntToStr2(sumfiles_integrityfail);
469
  // LabelXX.Caption := IntToStr2(sumfiles_integrityfail);
466
end;
470
end;
467
 
471
 
468
procedure TfrmIndexCreator.Copyuniquepathtoclipboard1Click(Sender: TObject);
472
procedure TfrmIndexCreator.Copyuniquepathtoclipboard1Click(Sender: TObject);
469
var
473
var
470
  s: string;
474
  s: string;
471
begin
475
begin
472
  s := uniqueFilename(LabeledEdit2.Text);
476
  s := uniqueFilename(LabeledEdit2.Text);
473
  Clipboard.AsText := s;
477
  Clipboard.AsText := s;
474
{$IFDEF VIATHINKSOFT}
478
{$IFDEF VIATHINKSOFT}
475
  if VtsSpecial(s) <> s then
479
  if VtsSpecial(s) <> s then
476
  begin
480
  begin
477
    s := s + #13#10 + VtsSpecial(s);
481
    s := s + #13#10 + VtsSpecial(s);
478
  end;
482
  end;
479
{$ENDIF}
483
{$ENDIF}
480
  ShowMessageFmt('Copied to clipboard:' + #13#10#13#10 + '%s', [s]);
484
  ShowMessageFmt('Copied to clipboard:' + #13#10#13#10 + '%s', [s]);
481
end;
485
end;
482
 
486
 
483
procedure TfrmIndexCreator.rgModusClick(Sender: TObject);
487
procedure TfrmIndexCreator.rgModusClick(Sender: TObject);
484
begin
488
begin
485
  cbSimulate.enabled := rgModus.ItemIndex <> modusValidation;
489
  cbSimulate.enabled := rgModus.ItemIndex <> modusValidation;
486
  cbNoDelete.enabled := rgModus.ItemIndex <> modusValidation;
490
  cbNoDelete.enabled := rgModus.ItemIndex <> modusValidation;
487
end;
491
end;
488
 
492
 
489
function TfrmIndexCreator.TableName: string;
493
function TfrmIndexCreator.TableName: string;
490
begin
494
begin
491
  Result := frmMain.TableName;
495
  Result := frmMain.TableName;
492
end;
496
end;
493
 
497
 
494
procedure TfrmIndexCreator.Rec(StartDir: string; const FileMask: string);
498
procedure TfrmIndexCreator.Rec(StartDir: string; const FileMask: string);
495
var
499
var
496
  SR: TSearchRec;
500
  SR: TSearchRec;
497
  DirList: TStrings;
501
  DirList: TStrings;
498
  IsFound: boolean;
502
  IsFound: boolean;
499
  i: Integer;
503
  i: Integer;
500
  UniqueStartDir: string;
504
  UniqueStartDir: string;
501
begin
505
begin
502
  StartDir := IncludeTrailingPathDelimiter(StartDir);
506
  StartDir := IncludeTrailingPathDelimiter(StartDir);
503
 
507
 
504
  i := 0;
508
  i := 0;
505
  conn.BeginTrans;
509
  conn.BeginTrans;
506
  IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
510
  IsFound := FindFirst(StartDir + FileMask, faAnyFile - faDirectory, SR) = 0;
507
  try
511
  try
508
    while IsFound do
512
    while IsFound do
509
    begin
513
    begin
510
      Inc(i);
514
      Inc(i);
511
      if i mod 1000 = 0 then // Only for performance
515
      if i mod 1000 = 0 then // Only for performance
512
      begin
516
      begin
513
        conn.CommitTrans;
517
        conn.CommitTrans;
514
        conn.BeginTrans;
518
        conn.BeginTrans;
515
      end;
519
      end;
516
      Application.ProcessMessages;
520
      Application.ProcessMessages;
517
      if Application.Terminated or StopRequest then
521
      if Application.Terminated or StopRequest then
518
        Abort;
522
        Abort;
519
 
523
 
520
      if UniqueStartDir = '' then
524
      if UniqueStartDir = '' then
521
        UniqueStartDir := uniqueFilename(StartDir);
525
        UniqueStartDir := uniqueFilename(StartDir);
522
      CheckFile(StartDir + SR.Name, UniqueStartDir + SR.Name);
526
      CheckFile(StartDir + SR.Name, UniqueStartDir + SR.Name);
523
      IsFound := FindNext(SR) = 0;
527
      IsFound := FindNext(SR) = 0;
524
    end;
528
    end;
525
  finally
529
  finally
526
    FindClose(SR);
530
    FindClose(SR);
527
    conn.CommitTrans;
531
    conn.CommitTrans;
528
  end;
532
  end;
529
 
533
 
530
  // Build a list of subdirectories
534
  // Build a list of subdirectories
531
  DirList := TStringList.Create;
535
  DirList := TStringList.Create;
532
  try
536
  try
533
    IsFound := FindFirst(StartDir + '*', faDirectory, SR) = 0;
537
    IsFound := FindFirst(StartDir + '*', faDirectory, SR) = 0;
534
    try
538
    try
535
      while IsFound do
539
      while IsFound do
536
      begin
540
      begin
537
        if (SR.Name <> '.') and (SR.Name <> '..') then
541
        if (SR.Name <> '.') and (SR.Name <> '..') then
538
        begin
542
        begin
539
          Application.ProcessMessages;
543
          Application.ProcessMessages;
540
          if Application.Terminated or StopRequest then
544
          if Application.Terminated or StopRequest then
541
            Abort;
545
            Abort;
542
 
546
 
543
          DirList.Add(StartDir + SR.Name);
547
          DirList.Add(StartDir + SR.Name);
544
        end;
548
        end;
545
        IsFound := FindNext(SR) = 0;
549
        IsFound := FindNext(SR) = 0;
546
      end;
550
      end;
547
    finally
551
    finally
548
      FindClose(SR);
552
      FindClose(SR);
549
    end;
553
    end;
550
 
554
 
551
    // Scan the list of subdirectories
555
    // Scan the list of subdirectories
552
    for i := 0 to DirList.Count - 1 do
556
    for i := 0 to DirList.Count - 1 do
553
    begin
557
    begin
554
      try
558
      try
555
        Rec(DirList[i], FileMask);
559
        Rec(DirList[i], FileMask);
556
      except
560
      except
557
        on E: Exception do
561
        on E: Exception do
558
        begin
562
        begin
559
          if E is EAbort then
563
          if E is EAbort then
560
            Abort;
564
            Abort;
561
          Memo2.Lines.Add('Unexpected error at directory ' + DirList[i] + ': ' +
565
          Memo2.Lines.Add('Unexpected error at directory ' + DirList[i] + ': ' +
562
            E.Message);
566
            E.Message);
563
        end;
567
        end;
564
      end;
568
      end;
565
    end;
569
    end;
566
  finally
570
  finally
567
    DirList.Free;
571
    DirList.Free;
568
  end;
572
  end;
569
end;
573
end;
570
 
574
 
571
procedure TfrmIndexCreator.DeleteAllFiles(mask: string = '');
575
procedure TfrmIndexCreator.DeleteAllFiles(mask: string = '');
572
begin
576
begin
573
  sumfiles_deleted := conn.GetScalar('select count(*) as cnt from ' + TableName
577
  sumfiles_deleted := conn.GetScalar('select count(*) as cnt from ' + TableName
574
    + ' where filename like ' + conn.SQLStringEscape(VtsSpecial(mask)));
578
    + ' where filename like ' + conn.SQLStringEscape(VtsSpecial(mask)));
575
  RedrawStats;
579
  RedrawStats;
576
 
580
 
577
  if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation) then
581
  if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation) then
578
  begin
582
  begin
579
    if (mask = '') or (mask = '%') then
583
    if (mask = '') or (mask = '%') then
580
      conn.ExecSQL('delete from ' + TableName)
584
      conn.ExecSQL('delete from ' + TableName)
581
    else
585
    else
582
      conn.ExecSQL('delete from ' + TableName + ' where filename like ' +
586
      conn.ExecSQL('delete from ' + TableName + ' where filename like ' +
583
        conn.SQLStringEscape(VtsSpecial(mask)));
587
        conn.SQLStringEscape(VtsSpecial(mask)));
584
  end;
588
  end;
585
end;
589
end;
586
 
590
 
587
procedure TfrmIndexCreator.DeleteVanishedFiles(mask: string = '');
591
procedure TfrmIndexCreator.DeleteVanishedFiles(mask: string = '');
588
 
592
 
589
{$IFDEF VIATHINKSOFT}
593
{$IFDEF VIATHINKSOFT}
590
var
594
var
591
  cacheAconnected: boolean;
595
  cacheAconnected: boolean;
592
  cacheBconnected: boolean;
596
  cacheBconnected: boolean;
-
 
597
  cacheRconnected: boolean;
593
{$ENDIF}
598
{$ENDIF}
594
  function AllowFileCheck(AFileName: string): boolean;
599
  function AllowFileCheck(AFileName: string): boolean;
595
  var
600
  var
596
    guid: string;
601
    guid: string;
597
  begin
602
  begin
598
    Result := false;
603
    Result := false;
599
{$IFDEF VIATHINKSOFT}
604
{$IFDEF VIATHINKSOFT}
600
    if StartsText('EHDD:\', AFileName) then
605
    if StartsText('EHDD:\', AFileName) then
601
    begin
606
    begin
602
      if not cacheAconnected and SysUtils.DirectoryExists(GUID_EHDD_A) then
607
      if not cacheAconnected and SysUtils.DirectoryExists(GUID_EHDD_A) then
603
      begin
608
      begin
604
        cacheAconnected := true;
609
        cacheAconnected := true;
605
      end;
610
      end;
606
      if not cacheBconnected and SysUtils.DirectoryExists(GUID_EHDD_B) then
611
      if not cacheBconnected and SysUtils.DirectoryExists(GUID_EHDD_B) then
607
      begin
612
      begin
608
        cacheBconnected := true;
613
        cacheBconnected := true;
609
      end;
614
      end;
-
 
615
      if not cacheRconnected and SysUtils.DirectoryExists(GUID_EHDD_R) then
-
 
616
      begin
-
 
617
        cacheRconnected := true;
-
 
618
      end;
610
      Result := cacheAconnected or cacheBconnected;
619
      Result := cacheAconnected or cacheBconnected or cacheRconnected;
611
    end
620
    end
612
    else
621
    else
613
{$ENDIF}
622
{$ENDIF}
614
      if StartsText('\\?\Volume', AFileName) then
623
      if StartsText('\\?\Volume', AFileName) then
615
      begin
624
      begin
616
        guid := Copy(AFileName, 1, 49);
625
        guid := Copy(AFileName, 1, 49);
617
        if EndsText('\', guid) then // should always happen
626
        if EndsText('\', guid) then // should always happen
618
        begin
627
        begin
619
          // TODO: cache this result somehow, so that DirectoryExists() does not need to be called all the time
628
          // TODO: cache this result somehow, so that DirectoryExists() does not need to be called all the time
620
          if SysUtils.DirectoryExists(guid) then // is drive connected/existing?
629
          if SysUtils.DirectoryExists(guid) then // is drive connected/existing?
621
          begin
630
          begin
622
            Result := true;
631
            Result := true;
623
          end;
632
          end;
624
        end;
633
        end;
625
      end
634
      end
626
      else
635
      else
627
      begin
636
      begin
628
        // TODO: Einen Code für Netzlaufwerke machen: Wir dürfen nur Dateien löschen,
637
        // TODO: Einen Code für Netzlaufwerke machen: Wir dürfen nur Dateien löschen,
629
        // wenn das Netzlaufwerk wirklich da ist.
638
        // wenn das Netzlaufwerk wirklich da ist.
630
      end;
639
      end;
631
  end;
640
  end;
632
 
641
 
633
  function FileDoesExist(AFileName: string): boolean;
642
  function FileDoesExist(AFileName: string): boolean;
634
  begin
643
  begin
635
{$IFDEF VIATHINKSOFT}
644
{$IFDEF VIATHINKSOFT}
636
    if StartsText('EHDD:\', AFileName) then
645
    if StartsText('EHDD:\', AFileName) then
637
    begin
646
    begin
638
      // Attention: AllowFileCheck must be called to initialize cacheAconnected and cacheBconnected
647
      // Attention: AllowFileCheck must be called to initialize cacheAconnected and cacheBconnected
639
 
648
 
640
      if cacheAconnected and FileExists(StringReplace(AFileName, 'EHDD:\',
649
      if cacheAconnected and FileExists(StringReplace(AFileName, 'EHDD:\',
641
        GUID_EHDD_A, [])) then
650
        GUID_EHDD_A, [])) then
642
        exit(true);
651
        exit(true);
643
 
652
 
644
      if cacheBconnected and FileExists(StringReplace(AFileName, 'EHDD:\',
653
      if cacheBconnected and FileExists(StringReplace(AFileName, 'EHDD:\',
645
        GUID_EHDD_B, [])) then
654
        GUID_EHDD_B, [])) then
646
        exit(true);
655
        exit(true);
-
 
656
 
-
 
657
      if cacheBconnected and FileExists(StringReplace(AFileName, 'EHDD:\',
-
 
658
        GUID_EHDD_R, [])) then
-
 
659
        exit(true);
647
 
660
 
648
      exit(false);
661
      exit(false);
649
    end;
662
    end;
650
{$ENDIF}
663
{$ENDIF}
651
    exit(FileExists(AFileName));
664
    exit(FileExists(AFileName));
652
  end;
665
  end;
653
 
666
 
654
var
667
var
655
  filename: string;
668
  filename: string;
656
  q: TADODataSet;
669
  q: TADODataSet;
657
  fFileName: TField;
670
  fFileName: TField;
658
  i: int64;
671
  i: int64;
659
begin
672
begin
660
  if mask <> '' then
673
  if mask <> '' then
661
    q := conn.GetTable('select filename from ' + TableName +
674
    q := conn.GetTable('select filename from ' + TableName +
662
      ' where filename like ' + conn.SQLStringEscape(VtsSpecial(mask)))
675
      ' where filename like ' + conn.SQLStringEscape(VtsSpecial(mask)))
663
  else
676
  else
664
    q := conn.GetTable('select filename from ' + TableName);
677
    q := conn.GetTable('select filename from ' + TableName);
665
  try
678
  try
666
    i := 0;
679
    i := 0;
667
    fFileName := q.FieldByName('filename');
680
    fFileName := q.FieldByName('filename');
668
    while not q.Eof do
681
    while not q.Eof do
669
    begin
682
    begin
670
      filename := fFileName.AsString;
683
      filename := fFileName.AsString;
671
 
684
 
672
      if AllowFileCheck(filename) and not FileDoesExist(filename) then
685
      if AllowFileCheck(filename) and not FileDoesExist(filename) then
673
      begin
686
      begin
674
        if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
687
        if not cbSimulate.Checked and (rgModus.ItemIndex <> modusValidation)
675
        then
688
        then
676
        begin
689
        begin
677
          conn.ExecSQL('delete from ' + TableName + ' where filename = ' +
690
          conn.ExecSQL('delete from ' + TableName + ' where filename = ' +
678
            conn.SQLStringEscape(filename));
691
            conn.SQLStringEscape(filename));
679
        end;
692
        end;
680
        Inc(sumfiles_deleted);
693
        Inc(sumfiles_deleted);
681
        if cbVerboseLogs.Checked then
694
        if cbVerboseLogs.Checked then
682
          Memo2.Lines.Add('Deleted: ' + filename);
695
          Memo2.Lines.Add('Deleted: ' + filename);
683
        RedrawStats;
696
        RedrawStats;
684
      end;
697
      end;
685
 
698
 
686
      Inc(i);
699
      Inc(i);
687
      if i mod 100 = 0 then
700
      if i mod 100 = 0 then
688
      begin
701
      begin
689
        Label1.Caption := MinimizeName(filename, Label1.Canvas, Label1.Width);
702
        Label1.Caption := MinimizeName(filename, Label1.Canvas, Label1.Width);
690
        Application.ProcessMessages;
703
        Application.ProcessMessages;
691
        if Application.Terminated or StopRequest then
704
        if Application.Terminated or StopRequest then
692
          Abort;
705
          Abort;
693
      end;
706
      end;
694
 
707
 
695
      q.Next;
708
      q.Next;
696
    end;
709
    end;
697
  finally
710
  finally
698
    FreeAndNil(q);
711
    FreeAndNil(q);
699
  end;
712
  end;
700
end;
713
end;
701
 
714
 
702
procedure TfrmIndexCreator.IndexDrive(initialdir: string);
715
procedure TfrmIndexCreator.IndexDrive(initialdir: string);
703
begin
716
begin
704
  if not cbNoDelete.Checked and not cbSimulate.Checked and
717
  if not cbNoDelete.Checked and not cbSimulate.Checked and
705
    (rgModus.ItemIndex <> modusValidation) then
718
    (rgModus.ItemIndex <> modusValidation) then
706
  begin
719
  begin
707
    if rgModus.ItemIndex = modusRecreate then
720
    if rgModus.ItemIndex = modusRecreate then
708
    begin
721
    begin
709
      DeleteAllFiles(uniqueFilename(IncludeTrailingPathDelimiter
722
      DeleteAllFiles(uniqueFilename(IncludeTrailingPathDelimiter
710
        (initialdir)) + '%');
723
        (initialdir)) + '%');
711
    end
724
    end
712
    else
725
    else
713
    begin
726
    begin
714
      DeleteVanishedFiles
727
      DeleteVanishedFiles
715
        (uniqueFilename(IncludeTrailingPathDelimiter(initialdir)) + '%');
728
        (uniqueFilename(IncludeTrailingPathDelimiter(initialdir)) + '%');
716
    end;
729
    end;
717
  end;
730
  end;
718
 
731
 
719
  Rec(IncludeTrailingPathDelimiter(initialdir), '*');
732
  Rec(IncludeTrailingPathDelimiter(initialdir), '*');
720
end;
733
end;
721
 
734
 
722
procedure TfrmIndexCreator.Button1Click(Sender: TObject);
735
procedure TfrmIndexCreator.Button1Click(Sender: TObject);
723
begin
736
begin
724
  sumsize := 0;
737
  sumsize := 0;
725
  sumfiles := 0;
738
  sumfiles := 0;
726
  sumfiles_new := 0;
739
  sumfiles_new := 0;
727
  sumfiles_updated := 0;
740
  sumfiles_updated := 0;
728
  sumfiles_error := 0;
741
  sumfiles_error := 0;
729
  sumfiles_deleted := 0;
742
  sumfiles_deleted := 0;
730
  sumfiles_integrityfail := 0;
743
  sumfiles_integrityfail := 0;
731
 
744
 
732
  Label1.Caption := 'Please wait...';
745
  Label1.Caption := 'Please wait...';
733
  Label5.Caption := '0';
746
  Label5.Caption := '0';
734
  Label6.Caption := '0';
747
  Label6.Caption := '0';
735
  Label7.Caption := '0';
748
  Label7.Caption := '0';
736
  Label9.Caption := '0';
749
  Label9.Caption := '0';
737
  Label11.Caption := '0';
750
  Label11.Caption := '0';
738
  Label12.Caption := '0';
751
  Label12.Caption := '0';
739
  Application.ProcessMessages;
752
  Application.ProcessMessages;
740
 
753
 
741
  EnableDisableControls(false);
754
  EnableDisableControls(false);
742
  try
755
  try
743
    if not SysUtils.DirectoryExists(LabeledEdit2.Text) then
756
    if not SysUtils.DirectoryExists(LabeledEdit2.Text) then
744
    begin
757
    begin
745
      raise Exception.CreateFmt('Directory %s not found.', [LabeledEdit2.Text]);
758
      raise Exception.CreateFmt('Directory %s not found.', [LabeledEdit2.Text]);
746
    end;
759
    end;
747
 
760
 
748
    IndexDrive(LabeledEdit2.Text);
761
    IndexDrive(LabeledEdit2.Text);
749
 
762
 
750
    (*
763
    (*
751
      if not Application.Terminated or StopRequest then
764
      if not Application.Terminated or StopRequest then
752
      begin
765
      begin
753
      ShowMessage('Finished');
766
      ShowMessage('Finished');
754
      end;
767
      end;
755
    *)
768
    *)
756
  finally
769
  finally
757
    if not StopRequest then EnableDisableControls(true);
770
    if not StopRequest then EnableDisableControls(true);
758
  end;
771
  end;
759
 
772
 
760
  if not StopRequest then
773
  if not StopRequest then
761
  begin
774
  begin
762
    Beep;
775
    Beep;
763
    Label1.Caption := 'Done.';
776
    Label1.Caption := 'Done.';
764
    Application.ProcessMessages;
777
    Application.ProcessMessages;
765
  end;
778
  end;
766
end;
779
end;
767
 
780
 
768
procedure TfrmIndexCreator.FormClose(Sender: TObject; var Action: TCloseAction);
781
procedure TfrmIndexCreator.FormClose(Sender: TObject; var Action: TCloseAction);
769
begin
782
begin
770
  StopRequest := true;
783
  StopRequest := true;
771
  Action := caFree; // TODO: müssen wir warten bis der prozess angehalten ist?
784
  Action := caFree; // TODO: müssen wir warten bis der prozess angehalten ist?
772
end;
785
end;
773
 
786
 
774
procedure TfrmIndexCreator.FormShow(Sender: TObject);
787
procedure TfrmIndexCreator.FormShow(Sender: TObject);
775
var
788
var
776
  ini: TMemIniFile;
789
  ini: TMemIniFile;
777
begin
790
begin
778
  ini := frmMain.ini;
791
  ini := frmMain.ini;
779
  rgModus.ItemIndex := ini.ReadInteger('IndexCreator', 'DefaultMode', modusUpdate);
792
  rgModus.ItemIndex := ini.ReadInteger('IndexCreator', 'DefaultMode', modusUpdate);
780
  cbNoDelete.Checked := ini.ReadBool('IndexCreator', 'DefaultCheckVanished', false);
793
  cbNoDelete.Checked := ini.ReadBool('IndexCreator', 'DefaultCheckVanished', false);
781
  cbVerboseLogs.Checked := ini.ReadBool('IndexCreator', 'DefaultVerboseLogs', false);
794
  cbVerboseLogs.Checked := ini.ReadBool('IndexCreator', 'DefaultVerboseLogs', false);
782
  cbSimulate.Checked := ini.ReadBool('IndexCreator', 'DefaultSimulate', false);
795
  cbSimulate.Checked := ini.ReadBool('IndexCreator', 'DefaultSimulate', false);
783
  LabeledEdit2.Text := ini.ReadString('IndexCreator', 'DefaultDir', 'C:\');
796
  LabeledEdit2.Text := ini.ReadString('IndexCreator', 'DefaultDir', 'C:\');
784
end;
797
end;
785
 
798
 
786
procedure TfrmIndexCreator.Button2Click(Sender: TObject);
799
procedure TfrmIndexCreator.Button2Click(Sender: TObject);
787
begin
800
begin
788
  StopRequest := true;
801
  StopRequest := true;
789
  Close;
802
  Close;
790
end;
803
end;
791
 
804
 
792
procedure TfrmIndexCreator.Button4Click(Sender: TObject);
805
procedure TfrmIndexCreator.Button4Click(Sender: TObject);
793
var
806
var
794
  i: Integer;
807
  i: Integer;
795
  s: string;
808
  s: string;
796
begin
809
begin
797
  sumsize := 0;
810
  sumsize := 0;
798
  sumfiles := 0;
811
  sumfiles := 0;
799
  sumfiles_new := 0;
812
  sumfiles_new := 0;
800
  sumfiles_updated := 0;
813
  sumfiles_updated := 0;
801
  sumfiles_error := 0;
814
  sumfiles_error := 0;
802
  sumfiles_deleted := 0;
815
  sumfiles_deleted := 0;
803
 
816
 
804
  Label1.Caption := 'Please wait...';
817
  Label1.Caption := 'Please wait...';
805
  Label5.Caption := '0';
818
  Label5.Caption := '0';
806
  Label6.Caption := '0';
819
  Label6.Caption := '0';
807
  Label7.Caption := '0';
820
  Label7.Caption := '0';
808
  Label9.Caption := '0';
821
  Label9.Caption := '0';
809
  Label11.Caption := '0';
822
  Label11.Caption := '0';
810
  Label12.Caption := '0';
823
  Label12.Caption := '0';
811
  Application.ProcessMessages;
824
  Application.ProcessMessages;
812
 
825
 
813
  EnableDisableControls(false);
826
  EnableDisableControls(false);
814
  try
827
  try
815
    // if fileexists('tmp') then memo1.lines.LoadFromFile('tmp');
828
    // if fileexists('tmp') then memo1.lines.LoadFromFile('tmp');
816
    for i := Memo1.Lines.Count - 1 downto 0 do
829
    for i := Memo1.Lines.Count - 1 downto 0 do
817
    begin
830
    begin
818
      s := Memo1.Lines.strings[i];
831
      s := Memo1.Lines.strings[i];
819
      if Trim(s) <> '' then
832
      if Trim(s) <> '' then
820
      begin
833
      begin
821
        LabeledEdit2.Text := s;
834
        LabeledEdit2.Text := s;
822
 
835
 
823
        if not SysUtils.DirectoryExists(LabeledEdit2.Text) then
836
        if not SysUtils.DirectoryExists(LabeledEdit2.Text) then
824
        begin
837
        begin
825
          raise Exception.CreateFmt('Directory %s not found.',
838
          raise Exception.CreateFmt('Directory %s not found.',
826
            [LabeledEdit2.Text]);
839
            [LabeledEdit2.Text]);
827
        end;
840
        end;
828
 
841
 
829
        IndexDrive(LabeledEdit2.Text);
842
        IndexDrive(LabeledEdit2.Text);
830
      end;
843
      end;
831
      Memo1.Lines.Delete(i);
844
      Memo1.Lines.Delete(i);
832
      // memo1.lines.SaveToFile('tmp');
845
      // memo1.lines.SaveToFile('tmp');
833
    end;
846
    end;
834
 
847
 
835
    (*
848
    (*
836
      if not Application.Terminated or StopRequest then
849
      if not Application.Terminated or StopRequest then
837
      begin
850
      begin
838
      ShowMessage('Finished');
851
      ShowMessage('Finished');
839
      end;
852
      end;
840
    *)
853
    *)
841
  finally
854
  finally
842
    EnableDisableControls(true);
855
    EnableDisableControls(true);
843
  end;
856
  end;
844
 
857
 
845
  Beep;
858
  Beep;
846
  Label1.Caption := 'Done.';
859
  Label1.Caption := 'Done.';
847
  Application.ProcessMessages;
860
  Application.ProcessMessages;
848
end;
861
end;
849
 
862
 
850
procedure TfrmIndexCreator.EnableDisableControls(enabled: boolean);
863
procedure TfrmIndexCreator.EnableDisableControls(enabled: boolean);
851
begin
864
begin
852
  rgModus.enabled := enabled;
865
  rgModus.enabled := enabled;
853
  cbNoDelete.enabled := enabled and (rgModus.ItemIndex <> modusValidation);
866
  cbNoDelete.enabled := enabled and (rgModus.ItemIndex <> modusValidation);
854
  cbVerboseLogs.enabled := enabled;
867
  cbVerboseLogs.enabled := enabled;
855
  cbSimulate.enabled := enabled and (rgModus.ItemIndex <> modusValidation);
868
  cbSimulate.enabled := enabled and (rgModus.ItemIndex <> modusValidation);
856
  Button1.enabled := enabled;
869
  Button1.enabled := enabled;
857
  LabeledEdit2.enabled := enabled;
870
  LabeledEdit2.enabled := enabled;
858
  Memo1.enabled := enabled;
871
  Memo1.enabled := enabled;
859
  Button4.enabled := enabled;
872
  Button4.enabled := enabled;
860
end;
873
end;
861
 
874
 
862
end.
875
end.
863
 
876