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 |