source: trunk/gsinstaller/fileCopier.cpp@ 11664

Last change on this file since 11664 was 11664, checked in by mdewsnip, 16 years ago

Fixed the line endings... for real this time, I hope.

  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1#include "fileCopier.h"
2
3#include <stdlib.h>
4#include <stdio.h>
5//#include <dir.h>
6#include <direct.h>
7
8#include <fstream.h>
9
10fileCopySet::fileCopySet()
11{
12 // do we need this - they're FilePath's, not pointers
13 // this->sourceDir = NULL;
14 // this->destDir = NULL;
15}
16
17fileCopySet::fileCopySet(string label, FileVector files, FilePath &from, FilePath &to)
18{
19 this->fileList = files;
20 this->sourceDir = from;
21 this->label = label;
22 this->destDir = to;
23 this->dataSize = 0;
24 this->dataFiles = 0;
25
26 FileVector::iterator here = files.begin();
27 FileVector::iterator end = files.end();
28
29 while (here != end)
30 {
31 unsigned long size, files;
32 here->getFileSize(size, files);
33 this->dataSize += size;
34 this->dataFiles += files;
35 here ++;
36 }
37}
38
39/**
40 * Get the destination file name for a given source file; source and destination
41 * directory locations are obtained from the object
42 */
43char *fileCopySet::destination(File *file)
44{
45 const char *oldname = file->cString();
46 char *newname = (char *) malloc(strlen(oldname) - strlen(this->sourceDir.cString()) + strlen(this->destDir.cString()) + 1);
47
48 if (newname != NULL)
49 {
50 strcpy(newname, this->destDir.cString());
51 strcat(newname, &oldname[strlen(this->sourceDir.cString())]);
52 }
53
54 return newname;
55}
56
57bool fileCopySet::ensureParent(FilePath &child, fileCopyMonitor *monitor)
58{ FilePath *parentName = child.parent();
59
60 // check for existence of parent
61 if (parentName->exists() == false)
62 { // ensure the grandparent exists
63 if (!this->ensureParent(*parentName, monitor))
64 { return false;
65 }
66
67 // create parent directory
68 _mkdir(parentName->cString());
69
70 // log the creation - we don't give a source - it's not needed for directories
71 if (monitor != NULL)
72 { monitor->createdDir(parentName->cString());
73 }
74 }
75 delete parentName;
76 return true;
77}
78
79/**
80 * Copy a particular file to its destination
81 */
82bool fileCopySet::copyFile(File *file, fileCopyMonitor *monitor, copyProgressBar *progressBar)
83{
84 unsigned long copied = 0;
85 unsigned long bytes_read, bytes_written;
86 static unsigned char buffer[65536];
87 FILE *read_handle, *write_handle;
88 char *destination;
89
90 // get destination as a char[] block; will free it later
91 destination = this->destination(file);
92
93 // ensure that the parent exists, as some install requirements are for files with
94 // directory paths which may not preexist
95 FilePath destPath(destination);
96 this->ensureParent(destPath, monitor);
97
98 // get read and write file handles
99 read_handle = fopen(file->cString(), "rb");
100 if (read_handle == NULL)
101 {
102 return false;
103 }
104 write_handle = fopen(destination, "wb");
105 if (write_handle == NULL)
106 {
107 fclose(read_handle);
108 return false;
109 }
110
111 while (copied < file->getFileSize())
112 {
113 // TODO: lock
114 // read so many bytes
115 if (file->getFileSize() - copied < 65536)
116 {
117 bytes_read = file->getFileSize() - copied;
118 }
119 else
120 {
121 bytes_read = 65536;
122 }
123 bytes_read = fread((void *) buffer, 1, bytes_read, read_handle);
124
125 // write so many bytes
126 bytes_written = fwrite((void *) buffer, 1, bytes_read, write_handle);
127
128 // TODO: unlock
129
130 // note new bytes copied
131 copied += bytes_written;
132// this->dataSize += bytes_written;
133 }
134 fclose(read_handle);
135 fclose(write_handle);
136
137// this->dataFiles += 1;
138
139 // free destination filename text
140 if (monitor != NULL)
141 {
142 monitor->copiedFile(file->cString(), destination);
143 }
144 delete destination;
145 return true;
146}
147
148/**
149 * Copy a file "object" (may be a directory or a "proper" file) to it's
150 * destination
151 */
152void fileCopySet::copy(File *file, fileCopyMonitor *monitor, copyProgressBar *progressBar)
153{
154 // just skip this file if it doesn't exist
155 if (file->exists() == false)
156 {
157 return;
158 }
159
160 // if a directory, scan it.
161 if (file->isDirectory())
162 {
163 // get destination directory
164 char *thisDestDir = this->destination(file);
165 FilePath destPath(thisDestDir);
166
167 // create a directory if needsbe
168 if (destPath.exists() == false)
169 {
170 _mkdir(thisDestDir);
171
172 // note amount of data copied
173 // this->copied += file->getRawFileSize();
174
175 // note for uninstall the action done
176 if (monitor != NULL)
177 {
178 monitor->copiedDir(destPath.pathString());
179 }
180 }
181
182 // copy children
183 vector<File>::iterator here = file->childBegin();
184 vector<File>::iterator end = file->childEnd();
185 while (here != end)
186 {
187 this->copy(here, monitor, progressBar);
188 here ++;
189 }
190
191 // delete constructed destination name
192 delete thisDestDir;
193 }
194
195 // not a directory; just copy the file
196 else
197 {
198 // copy file itself
199 this->copyFile(file, monitor, progressBar);
200 }
201
202 if (progressBar != NULL)
203 { progressBar->done(file->getRawFileSize());
204 }
205}
206
207void fileCopySet::copy(fileCopyMonitor *monitor, copyProgressBar *progressBar)
208{
209 FileVector::iterator here = fileList.begin();
210 FileVector::iterator end = fileList.end();
211 while (here != end)
212 {
213 this->copy(here, monitor, progressBar);
214 here ++;
215 }
216}
217
218unsigned long fileCopySet::getCopiedSize(DiskSpace &space)
219{
220 // initialise counters for size
221 unsigned long copiedSize = 0;
222
223 // iterate through our list of files to obtain total space requirement
224 FileVector::iterator here = fileList.begin();
225 FileVector::iterator end = fileList.end();
226 while (here != end)
227 {
228 copiedSize += here->getDiskSpace(space);
229 here ++;
230 }
231 return copiedSize;
232}
233
234unsigned long fileCopySet::getOriginalSize()
235{
236 // initialise counters for size
237 return this->dataSize;
238}
239
240unsigned long fileCopySet::getOriginalFiles()
241{
242 // initialise counters for size
243 return this->dataFiles;
244}
245
246/**
247 * Perform a check on the total space available at the destination; if not
248 * enough then return false to indicate the error state
249 */
250bool fileCopier::checkSpace()
251{
252 fileCopySetList localSet = this->list;
253
254 this->progressBar.message("Checking disk space requirements");
255
256 do
257 {
258 unsigned int i = 0;
259
260 // get destination root and use it to obtain space check information
261 FilePath *destRoot = localSet[0].destDir.root();
262 DiskSpace space(destRoot->cString());
263
264 // check that diskspace checking is functional
265 if (space.initialisedOk() == false)
266 {
267 delete destRoot;
268 return false;
269 }
270
271 // get size of the first set
272 unsigned long copiedSize = localSet[0].getCopiedSize(space);
273
274 // dispose of the first set
275 localSet.erase(localSet.begin());
276
277 // get all remaining sets and in turn if they share the root with
278 // the first root, add their size to the count and remove them from
279 // the local list of sets; otherwise skip
280 while (i < localSet.size())
281 {
282 // get a new root object for this set's destination
283 FilePath *p = localSet[i].destDir.root();
284
285 if (*destRoot == *p)
286 {
287 copiedSize += localSet[i].getCopiedSize(space);
288 localSet.erase(localSet.begin() + i);
289 }
290 else
291 {
292 i ++;
293 }
294
295 // delete the constructed root
296 delete p;
297 }
298
299 // dispose of destination root
300 delete destRoot;
301
302 // return false if not enough space
303 if (space.totalFreeSpace() < copiedSize)
304 {
305 return false;
306 }
307
308 } while (localSet.size() != 0);
309
310
311 // record size and initialise the progressbar with the same
312 this->dataSize = 0;
313 this->dataFiles = 0;
314 for (unsigned int i = 0; i < this->list.size(); i ++)
315 {
316 this->dataSize += this->list[i].getOriginalSize();
317 this->dataFiles += this->list[i].getOriginalFiles();
318 }
319 this->progressBar.init(this->dataSize, this->dataFiles);
320
321 // return postive check
322 return true;
323}
324
325fileCopier::fileCopier(fileCopyMonitor *monitor, fileCopySetList &_list)
326{
327 this->list = _list;
328 this->dataSize = 0;
329 this->copied = 0;
330 this->dataFiles = 0;
331 this->monitor = monitor;
332
333 this->progressBar.show();
334 this->progressBar.message("Initialising");
335}
336
337fileCopier::fileCopier(fileCopyMonitor *monitor)
338{
339 this->dataSize = 0;
340 this->copied = 0;
341 this->dataFiles = 0;
342 this->monitor = monitor;
343
344 this->progressBar.show();
345 this->progressBar.message("Initialising");
346}
347
348void fileCopier::addSet(fileCopySet &set)
349{ this->list.push_back(set);
350 this->progressBar.message("Gathering files to copy");
351}
352
353// Do the actual file copy
354void fileCopier::copy()
355{
356 fileCopySetList::iterator here = list.begin();
357 fileCopySetList::iterator end = list.end();
358
359 // Tell the user what is happening
360 char buffer[100];
361 sprintf(buffer, "Copying %3.1fMb of files", (double) this->dataSize / (double) (1024 * 1024));
362 this->progressBar.message(buffer);
363 this->progressBar.setStartTime();
364
365 // Copy each file set individually, using the progress bar as a monitor
366 while (here != end)
367 {
368 here->copy(this->monitor, &this->progressBar);
369 here ++;
370 }
371
372 // Close the progress bar, as it is no longer needed
373 this->progressBar.close();
374}
Note: See TracBrowser for help on using the repository browser.