forked from gligli/SuperCopier2
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathSCAnsiBufferedCopier.pas
More file actions
166 lines (139 loc) · 5.6 KB
/
Copy pathSCAnsiBufferedCopier.pas
File metadata and controls
166 lines (139 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
{
This file is part of SuperCopier2.
SuperCopier2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SuperCopier2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
}
unit SCAnsiBufferedCopier;
interface
uses
Windows,Messages,SCCopier;
type
TAnsiBufferedCopier=class(TCopier)
private
Buffer:array of byte;
protected
procedure SetBufferSize(Value:cardinal);override;
public
function DoCopy:Boolean;override;
end;
implementation
uses SCCommon,SCLocStrings,SCWin32;
//******************************************************************************
//******************************************************************************
//******************************************************************************
// TAnsiBufferedCopier: descendant de TCopier, copie bufferisée simple en mode
// ansi (Pour Win9x)
//******************************************************************************
//******************************************************************************
//******************************************************************************
//******************************************************************************
// SetBufferSize: fixe la taille du buffer de copie
//******************************************************************************
procedure TAnsiBufferedCopier.SetBufferSize(Value:cardinal);
begin
if Value<>FBufferSize then
begin
SetLength(Buffer,Value);
FBufferSize:=Value;
end;
end;
//******************************************************************************
// DoCopy: renvoie false si la copie échoue
//******************************************************************************
function TAnsiBufferedCopier.DoCopy:boolean;
var HSrc,HDest:THandle;
SourceFile,DestFile:String;
BytesRead,BytesWritten:Cardinal;
ContinueCopy:Boolean;
LastError:Cardinal;
begin
Assert(Assigned(OnCopyProgress),'OnCopyProgress not assigned');
Result:=True;
with CurrentCopy do
begin
CopiedSize:=0;
SkippedSize:=0;
SourceFile:=FileItem.SrcFullName;
DestFile:=FileItem.DestFullName;
Inc(FileItem.CopyTryCount);
try
HSrc:=INVALID_HANDLE_VALUE;
HDest:=INVALID_HANDLE_VALUE;
try
// on ouvre le fichier source
HSrc:=CreateFile(pchar(SourceFile),
GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN,
0);
RaiseCopyErrorIfNot(HSrc<>INVALID_HANDLE_VALUE);
// effacer les attributs du fichier de destination pour pouvoir l'ouvrir en écriture
FileItem.DestClearAttributes;
// on ouvre le fichier de destination
if NextAction<>cpaRetry then // doit-on reprendre le transfert?
begin
HDest:=CreateFile(pchar(DestFile),
GENERIC_WRITE,
FILE_SHARE_READ,
nil,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
end
else
begin
HDest:=CreateFile(pchar(DestFile),
GENERIC_WRITE,
FILE_SHARE_READ,
nil,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
// on se positionne a la fin du fichier de destination
SetFilePointer(HDest,0,FILE_END);
SkippedSize:=FileItem.DestSize;
Self.SkippedSize:=Self.SkippedSize+SkippedSize;
// et on se mets a la position correspondante dans le fichier source
SetFilePointer(HSrc,SkippedSize,FILE_BEGIN);
end;
RaiseCopyErrorIfNot(HDest<>INVALID_HANDLE_VALUE);
// on donne sa taille finale au fichier de destination (pour éviter la fragmentation)
RaiseCopyErrorIfNot(SetFileSize(HDest,FileItem.SrcSize));
// boucle principale de copie
repeat
RaiseCopyErrorIfNot(ReadFile(HSrc,Buffer[0],BufferSize,BytesRead,nil));
RaiseCopyErrorIfNot(WriteFile(HDest,Buffer[0],BytesRead,BytesWritten,nil));
CopiedSize:=CopiedSize+BytesWritten;
Self.CopiedSize:=Self.CopiedSize+BytesWritten;
ContinueCopy:=OnCopyProgress;
until ((CopiedSize+SkippedSize)>=FileItem.SrcSize) or (not ContinueCopy);
// copie de la date de modif
CopyFileAge(HSrc,HDest);
finally
LastError:=GetLastError;
// on déclare la position courrante dans le fichier destination comme fin de fichier
SetEndOfFile(HDest);
// fermeture des handles si ouverts
CloseHandle(HSrc);
CloseHandle(HDest);
SetLastError(LastError); // ne pas polluer le code d'erreur
NextAction:=cpaNextFile;
end;
except
on E:ECopyError do
begin
Result:=False;
CopyError;
end;
end;
end;
end;
end.