source: other-projects/trunk/gsinstaller/fileCopier.cpp@ 15927

Last change on this file since 15927 was 15927, checked in by anna, 14 years ago

The old method for checking free disk space overflows (returns a negative number) when the physical free disk space is bigger than 4G. So instead of comparing by byte, now we compare by K. The return type is also changed, from unsigned long to double.

  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 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 double 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 (double) copiedSize / (double) 1024;
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 char buffer[100];
306 sprintf(buffer, "Total free space on disk %3.1fMb, but the size of the copied collection is %3.1fMb", (double) space.totalFreeSpace() / (double) (1024), (double) copiedSize / (double) (1024));
307 MessageBox(0, buffer, "Greenstone Installer", MB_OK);
308
309 return false;
310 }
311
312 } while (localSet.size() != 0);
313
314
315 // record size and initialise the progressbar with the same
316 this->dataSize = 0;
317 this->dataFiles = 0;
318 for (unsigned int i = 0; i < this->list.size(); i ++)
319 {
320 this->dataSize += this->list[i].getOriginalSize();
321 this->dataFiles += this->list[i].getOriginalFiles();
322 }
323 this->progressBar.init(this->dataSize, this->dataFiles);
324
325 // return postive check
326 return true;
327}
328
329fileCopier::fileCopier(fileCopyMonitor *monitor, fileCopySetList &_list)
330{
331 this->list = _list;
332 this->dataSize = 0;
333 this->copied = 0;
334 this->dataFiles = 0;
335 this->monitor = monitor;
336
337 this->progressBar.show();
338 this->progressBar.message("Initialising");
339}
340
341fileCopier::fileCopier(fileCopyMonitor *monitor)
342{
343 this->dataSize = 0;
344 this->copied = 0;
345 this->dataFiles = 0;
346 this->monitor = monitor;
347
348 this->progressBar.show();
349 this->progressBar.message("Initialising");
350}
351
352void fileCopier::addSet(fileCopySet &set)
353{ this->list.push_back(set);
354 this->progressBar.message("Gathering files to copy");
355}
356
357// Do the actual file copy
358void fileCopier::copy()
359{
360 fileCopySetList::iterator here = list.begin();
361 fileCopySetList::iterator end = list.end();
362
363 // Tell the user what is happening
364 char buffer[100];
365 sprintf(buffer, "Copying %3.1fMb of files", (double) this->dataSize / (double) (1024 * 1024));
366 this->progressBar.message(buffer);
367 this->progressBar.setStartTime();
368
369 // Copy each file set individually, using the progress bar as a monitor
370 while (here != end)
371 {
372 here->copy(this->monitor, &this->progressBar);
373 here ++;
374 }
375
376 // Close the progress bar, as it is no longer needed
377 this->progressBar.close();
378}
Note: See TracBrowser for help on using the repository browser.