summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/filemanager.cpp372
1 files changed, 130 insertions, 242 deletions
diff --git a/library/filemanager.cpp b/library/filemanager.cpp
index adfe590..47af1c6 100644
--- a/library/filemanager.cpp
+++ b/library/filemanager.cpp
@@ -1,440 +1,328 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20
20#include "filemanager.h" 21#include "filemanager.h"
21#include "applnk.h" 22#include "applnk.h"
22 23
24/* QT */
25#include <qdir.h>
23#include <qfileinfo.h> 26#include <qfileinfo.h>
24#include <qtextstream.h> 27#include <qtextstream.h>
25 28
26#include <errno.h> 29/* STD */
27#include <stdlib.h> 30#include <stdlib.h>
28#include <unistd.h>
29#include <sys/stat.h> 31#include <sys/stat.h>
30#include <dirent.h>
31#ifdef Q_OS_MACX
32// MacOS X does not have sendfile.. :(
33// But maybe in the future.. !?
34# ifdef SENDFILE
35# include <sys/types.h>
36# include <sys/socket.h>
37# endif
38#else
39# include <sys/sendfile.h>
40#endif /* Q_OS_MACX */
41#include <fcntl.h>
42 32
43/*! 33/*!
44 \class FileManager 34 \class FileManager
45 \brief The FileManager class assists with AppLnk input/output. 35 \brief The FileManager class assists with AppLnk input/output.
46*/ 36*/
47 37
48/*! 38/*!
49 Constructs a FileManager. 39 Constructs a FileManager.
50*/ 40*/
51FileManager::FileManager() 41FileManager::FileManager()
52{ 42{
53} 43}
54 44
55/*! 45/*!
56 Destroys a FileManager. 46 Destroys a FileManager.
57*/ 47*/
58FileManager::~FileManager() 48FileManager::~FileManager()
59{ 49{
60
61} 50}
62 51
63/*! 52/*!
64 Saves \a data as the document specified by \a f. 53 Saves \a data as the document specified by \a f.
65 54
66 Returns whether the operation succeeded. 55 Returns whether the operation succeeded.
67*/ 56*/
68bool FileManager::saveFile( const DocLnk &f, const QByteArray &data ) 57bool FileManager::saveFile( const DocLnk &f, const QByteArray &data )
69{ 58{
70 QString fn = f.file() + ".new"; 59 QString fileName = f.file() + ".new";
71 ensurePathExists( fn ); 60 ensurePathExists( fileName );
72 QFile fl( fn ); 61 QFile file( fileName );
73 if ( !fl.open( IO_WriteOnly|IO_Raw ) ) { 62
74 qWarning("open failed"); 63 //write data in temporary .new file
75 return FALSE; 64 if ( !file.open( IO_WriteOnly|IO_Raw ) )
76 } 65 {
77 int total_written = fl.writeBlock( data ); 66 qWarning("open failed");
78 fl.close(); 67 return FALSE;
79 if ( total_written != int(data.size()) || !f.writeLink() ) {
80 QFile::remove( fn );
81 return FALSE;
82 } 68 }
83 qDebug("total written %d out of %d", total_written, data.size()); 69 int total_written = file.writeBlock( data );
84 // else rename the file... 70 file.close();
85 if ( !renameFile( fn.latin1(), f.file().latin1() ) ) { 71 //check if every was written
86 qWarning( "problem renaming file %s to %s, errno: %d", fn.latin1(), 72 if ( total_written != int(data.size()) || !f.writeLink() )
87 f.file().latin1(), errno ); 73 {
88 // remove the file... 74 QFile::remove( fileName );
75 return FALSE;
89 } 76 }
77 qDebug("total written %d out of %d", total_written, data.size());
78
79 //rename temporary .new file in original filenam
80 if ( !renameFile( fileName, f.file() ) )
81 QFile::remove( fileName);
90 return TRUE; 82 return TRUE;
91} 83}
92 84
93/*! 85/*!
94 Saves \a text as the document specified by \a f. 86 Saves \a text as the document specified by \a f.
95 87
96 The text is saved in UTF8 format. 88 The text is saved in UTF8 format.
97 89
98 Returns whether the operation succeeded. 90 Returns whether the operation succeeded.
99*/ 91*/
100bool FileManager::saveFile( const DocLnk &f, const QString &text ) 92bool FileManager::saveFile( const DocLnk &f, const QString &text )
101{ 93{
102 QString fn = f.file() + ".new"; 94 QString fileName = f.file() + ".new";
103 ensurePathExists( fn ); 95 ensurePathExists( fileName );
104 QFile fl( fn ); 96 QFile file( fileName );
105 if ( !fl.open( IO_WriteOnly|IO_Raw ) ) { 97
106 qWarning("open failed"); 98 //write data in temporary .new file
107 return FALSE; 99 if ( !file.open( IO_WriteOnly|IO_Raw ) )
100 {
101 qWarning("open failed");
102 return FALSE;
108 } 103 }
109 104
110 QCString cstr = text.utf8(); 105 QCString cstr = text.utf8();
111 int total_written; 106 int total_written;
112 total_written = fl.writeBlock( cstr.data(), cstr.length() ); 107 total_written = file.writeBlock( cstr.data(), cstr.length() );
113 fl.close(); 108 file.close();
114 if ( total_written != int(cstr.length()) || !f.writeLink() ) { 109 if ( total_written != int(cstr.length()) || !f.writeLink() )
115 QFile::remove( fn ); 110 {
116 return FALSE; 111 QFile::remove( fileName );
112 return FALSE;
117 } 113 }
118 // okay now rename the file..
119 if ( !renameFile( fn.latin1(), f.file().latin1() ) ) {
120 qWarning( "problem renaming file %s to %s, errno: %d", fn.latin1(),
121 f.file().latin1(), errno );
122 114
123 } 115 // okay now rename the file..
116 if ( !renameFile( fileName, f.file() ) )
117 QFile::remove( fileName);
124 return TRUE; 118 return TRUE;
125} 119}
126 120
127 121
128/*! 122/*!
129 Loads \a text from the document specified by \a f. 123 Loads \a text from the document specified by \a f.
130 124
131 The text is required to be in UTF8 format. 125 The text is required to be in UTF8 format.
132 126
133 Returns whether the operation succeeded. 127 Returns whether the operation succeeded.
134*/ 128*/
135bool FileManager::loadFile( const DocLnk &f, QString &text ) 129bool FileManager::loadFile( const DocLnk &f, QString &text )
136{ 130{
137 QString fn = f.file(); 131 QString fn = f.file();
138 QFile fl( fn ); 132 QFile fl( fn );
139 if ( !fl.open( IO_ReadOnly ) ) 133 if ( !fl.open( IO_ReadOnly ) )
140 return FALSE; 134 return FALSE;
141 QTextStream ts( &fl ); 135 QTextStream ts( &fl );
142#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 136#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
143 // The below should work, but doesn't in Qt 2.3.0 137 // The below should work, but doesn't in Qt 2.3.0
144 ts.setCodec( QTextCodec::codecForMib( 106 ) ); 138 ts.setCodec( QTextCodec::codecForMib( 106 ) );
145#else 139#else
146 ts.setEncoding( QTextStream::UnicodeUTF8 ); 140 ts.setEncoding( QTextStream::UnicodeUTF8 );
147#endif 141#endif
148 text = ts.read(); 142 text = ts.read();
149 fl.close(); 143 fl.close();
150 return TRUE; 144 return TRUE;
151} 145}
152 146
153 147
154/*! 148/*!
155 Loads \a ba from the document specified by \a f. 149 Loads \a ba from the document specified by \a f.
156 150
157 Returns whether the operation succeeded. 151 Returns whether the operation succeeded.
158*/ 152*/
159bool FileManager::loadFile( const DocLnk &f, QByteArray &ba ) 153bool FileManager::loadFile( const DocLnk &f, QByteArray &ba )
160{ 154{
161 QString fn = f.file(); 155 QString fn = f.file();
162 QFile fl( fn ); 156 QFile fl( fn );
163 if ( !fl.open( IO_ReadOnly ) ) 157 if ( !fl.open( IO_ReadOnly ) )
164 return FALSE; 158 return FALSE;
165 ba.resize( fl.size() ); 159 ba.resize( fl.size() );
166 if ( fl.size() > 0 ) 160 if ( fl.size() > 0 )
167 fl.readBlock( ba.data(), fl.size() ); 161 fl.readBlock( ba.data(), fl.size() );
168 fl.close(); 162 fl.close();
169 return TRUE; 163 return TRUE;
170} 164}
171 165
172/*! 166/*!
173 Copies the document specified by \a src to the document specified 167 Copies the document specified by \a src to the document specified
174 by \a dest. 168 by \a dest.
175 169
176 Returns whether the operation succeeded. 170 Returns whether the operation succeeded.
177*/ 171*/
178bool FileManager::copyFile( const AppLnk &src, const AppLnk &dest ) 172bool FileManager::copyFile( const AppLnk &src, const AppLnk &dest )
179{ 173{
180 QFile sf( src.file() ); 174 QFile srcFile( src.file() );
181 if ( !sf.open( IO_ReadOnly ) ) 175 if ( !srcFile.open( IO_ReadOnly ) )
182 return FALSE; 176 return FALSE;
183 177
184 QString fn = dest.file() + ".new"; 178 QString fileName = dest.file() + ".new";
185 ensurePathExists( fn ); 179
186 QFile df( fn ); 180 ensurePathExists( fileName );
187 if ( !df.open( IO_WriteOnly|IO_Raw ) )
188 return FALSE;
189 181
190 const int bufsize = 16384;
191 char buffer[bufsize];
192 bool ok = TRUE; 182 bool ok = TRUE;
193 int bytesRead = 0; 183 ok = copyFile( src.file(), fileName );
194 while ( ok && !sf.atEnd() ) {
195 bytesRead = sf.readBlock( buffer, bufsize );
196 if ( bytesRead < 0 )
197 ok = FALSE;
198 while ( ok && bytesRead > 0 ) {
199 int bytesWritten = df.writeBlock( buffer, bytesRead );
200 if ( bytesWritten < 0 )
201 ok = FALSE;
202 else
203 bytesRead -= bytesWritten;
204 }
205 }
206 184
207 if ( ok ) 185 if ( ok )
208 ok = dest.writeLink(); 186 ok = dest.writeLink();
209
210 if ( ok ) {
211 // okay now rename the file...
212 if ( !renameFile( fn.latin1(), dest.file().latin1() ) ) {
213 qWarning( "problem renaming file %s to %s, errno: %d", fn.latin1(),
214 dest.file().latin1(), errno );
215 // remove the tmp file, otherwise, it will just lay around...
216 QFile::remove( fn.latin1() );
217 }
218 } else {
219 QFile::remove( fn.latin1() );
220 }
221 187
188 if ( ok )
189 {
190 // okay now rename the file...
191 if ( !renameFile( fileName.latin1(), dest.file().latin1() ) )
192 // remove the tmp file, otherwise, it will just lay around...
193 QFile::remove( fileName.latin1() );
194 }
195 else
196 {
197 QFile::remove( fileName.latin1() );
198 }
222 return ok; 199 return ok;
223} 200}
224 201
225bool FileManager::copyFile( const QString & src, const QString & dest ) { 202bool FileManager::copyFile( const QString & src, const QString & dest )
226 bool success = true; 203{
227 struct stat status; 204 //open read file
228 int read_fd=0; 205 QFile srcFile( src );
229 int write_fd=0; 206 if( !srcFile.open( IO_ReadOnly|IO_Raw) )
230 struct stat stat_buf; 207 {
231 off_t offset = 0; 208 qWarning( "open read failed %s, %s", src.latin1(), dest.latin1() );
232 QFile srcFile(src); 209 return FALSE;
233 QFile destFile(dest);
234
235 if(!srcFile.open( IO_ReadOnly|IO_Raw)) {
236 return success = false;
237 }
238 read_fd = srcFile.handle();
239 if(read_fd != -1) {
240 fstat (read_fd, &stat_buf);
241 if( !destFile.open( IO_WriteOnly|IO_Raw ) )
242 return success = false;
243 write_fd = destFile.handle();
244 if(write_fd != -1) {
245 int err=0;
246 QString msg;
247#ifdef Q_OS_MACX
248#ifdef SENDFILE
249 /* FreeBSD does support a different kind of
250 * sendfile. (eilers)
251 * I took this from Very Secure FTPd
252 * Licence: GPL
253 * Author: Chris Evans
254 * sysdeputil.c
255 */
256 /* XXX - start_pos will truncate on 32-bit machines - can we
257 * say "start from current pos"?
258 */
259 off_t written = 0;
260 int retval = 0;
261 retval = sendfile(read_fd, write_fd, offset, stat_buf.st_size, NULL,
262 &written, 0);
263 /* Translate to Linux-like retval */
264 if (written > 0)
265 {
266 err = (int) written;
267 }
268#else /* SENDFILE */
269 err == -1;
270 msg = "FAILURE: Using unsupported function \"sendfile()\" Need Workaround !!";
271 success = false;
272# warning "Need workaround for sendfile!!(eilers)"
273#endif /* SENDFILE */
274
275#else
276 err = sendfile(write_fd, read_fd, &offset, stat_buf.st_size);
277 if( err == -1) {
278 switch(errno) {
279 case EBADF : msg = "The input file was not opened for reading or the output file was not opened for writing. ";
280 case EINVAL: msg = "Descriptor is not valid or locked. ";
281 case ENOMEM: msg = "Insufficient memory to read from in_fd.";
282 case EIO: msg = "Unspecified error while reading from in_fd.";
283 };
284 success = false;
285 }
286#endif /* Q_OS_MACX */
287 if( !success )
288 qWarning( msg );
289 } else {
290 qWarning("open write failed %s, %s",src.latin1(), dest.latin1());
291 success = false;
292 }
293 } else {
294 qWarning("open read failed %s, %s",src.latin1(), dest.latin1());
295 success = false;
296 }
297 srcFile.close();
298 destFile.close();
299 // Set file permissions
300 if( stat( (const char *) src, &status ) == 0 ) {
301 chmod( (const char *) dest, status.st_mode );
302 } 210 }
303 211
304 return success; 212 //open write file
305} 213 QFile destFile( dest );
306 214 if( !destFile.open( IO_WriteOnly|IO_Raw ) )
307 215 {
308bool FileManager::renameFile( const QString & src, const QString & dest ) { 216 qWarning( "open write failed %s, %s", src.latin1(), dest.latin1() );
309 if(copyFile( src, dest )) { 217 srcFile.close();
310 if(QFile::remove(src) ) { 218 return FALSE;
311 return true; 219 }
312 }
313 }
314 return false;
315}
316 220
317/* 221 //copy content
318bool FileManager::copyFile( const QString & src, const QString & dest ) { 222 const int bufsize = 16384;
319 bool success = true; 223 char buffer[bufsize];
320 struct stat status; 224 bool ok = TRUE;
321 int read_fd=0; 225 int bytesRead = 0;
322 int write_fd=0; 226 while ( ok && !srcFile.atEnd() )
323 struct stat stat_buf; 227 {
324 off_t offset = 0; 228 bytesRead = srcFile.readBlock( buffer, bufsize );
325 QFile srcFile(src); 229 if ( bytesRead < 0 )
326 QFile destFile(dest); 230 ok = FALSE;
327 231 while ( ok && bytesRead > 0 )
328 if(!srcFile.open( IO_ReadOnly|IO_Raw)) { 232 {
329 return success = false; 233 int bytesWritten = destFile.writeBlock( buffer, bytesRead );
330 } 234 if ( bytesWritten < 0 )
331 read_fd = srcFile.handle(); 235 ok = FALSE;
332 if(read_fd != -1) { 236 else
333 fstat (read_fd, &stat_buf); 237 bytesRead -= bytesWritten;
334 if( !destFile.open( IO_WriteOnly|IO_Raw ) ) 238 }
335 return success = false; 239 }
336 write_fd = destFile.handle(); 240 srcFile.close();
337 if(write_fd != -1) { 241 destFile.close();
338 int err=0;
339 QString msg;
340 err = sendfile(write_fd, read_fd, &offset, stat_buf.st_size);
341 if( err == -1) {
342 switch(err) {
343 case EBADF : msg = "The input file was not opened for reading or the output file was not opened for writing. ";
344 case EINVAL: msg = "Descriptor is not valid or locked. ";
345 case ENOMEM: msg = "Insufficient memory to read from in_fd.";
346 case EIO: msg = "Unspecified error while reading from in_fd.";
347 };
348 success = false;
349 }
350 } else {
351 qWarning("open write failed %s, %s",src.latin1(), dest.latin1());
352 success = false;
353 }
354 } else {
355 qWarning("open read failed %s, %s",src.latin1(), dest.latin1());
356 success = false;
357 }
358 srcFile.close();
359 destFile.close();
360 // Set file permissions 242 // Set file permissions
361 if( stat( (const char *) src, &status ) == 0 ) { 243 struct stat status;
362 chmod( (const char *) dest, status.st_mode ); 244 if( stat( (const char *) src, &status ) == 0 )
245 {
246 chmod( (const char *) dest, status.st_mode );
363 } 247 }
364 248 return ok;
365 return success;
366} 249}
367 250
368 251
369bool FileManager::renameFile( const QString & src, const QString & dest ) { 252bool FileManager::renameFile( const QString & src, const QString & dest )
370 if(copyFile( src, dest )) { 253{
371 if(QFile::remove(src) ) { 254 QDir dir( QFileInfo( src ).absFilePath() );
372 return true; 255 if ( !dir.rename( src, dest ) )
373 } 256 {
374 } 257 qWarning( "problem renaming file %s to %s", src, dest );
375 return false; 258 return false;
259 }
260 return true;
376} 261}
377*/
378 262
379/*! 263/*!
380 Opens the document specified by \a f as a readable QIODevice. 264 Opens the document specified by \a f as a readable QIODevice.
381 The caller must delete the return value. 265 The caller must delete the return value.
382 266
383 Returns 0 if the operation fails. 267 Returns 0 if the operation fails.
384*/ 268*/
385QIODevice* FileManager::openFile( const DocLnk& f ) 269QIODevice* FileManager::openFile( const DocLnk& f )
386{ 270{
387 QString fn = f.file(); 271 QString fn = f.file();
388 QFile* fl = new QFile( fn ); 272 QFile* fl = new QFile( fn );
389 if ( !fl->open( IO_ReadOnly ) ) { 273 if ( !fl->open( IO_ReadOnly ) )
390 delete fl; 274 {
275 delete fl;
391 fl = 0; 276 fl = 0;
392 } 277 }
393 return fl; 278 return fl;
394} 279}
395 280
396/*! 281/*!
397 Opens the document specified by \a f as a writable QIODevice. 282 Opens the document specified by \a f as a writable QIODevice.
398 The caller must delete the return value. 283 The caller must delete the return value.
399 284
400 Returns 0 if the operation fails. 285 Returns 0 if the operation fails.
401*/ 286*/
402QIODevice* FileManager::saveFile( const DocLnk& f ) 287QIODevice* FileManager::saveFile( const DocLnk& f )
403{ 288{
404 QString fn = f.file(); 289 QString fn = f.file();
405 ensurePathExists( fn ); 290 ensurePathExists( fn );
406 QFile* fl = new QFile( fn ); 291 QFile* fl = new QFile( fn );
407 if ( fl->open( IO_WriteOnly ) ) { 292 if ( fl->open( IO_WriteOnly ) )
408 f.writeLink(); 293 {
409 } else { 294 f.writeLink();
410 delete fl; 295 }
296 else
297 {
298 delete fl;
411 fl = 0; 299 fl = 0;
412 } 300 }
413 return fl; 301 return fl;
414} 302}
415 303
416/*! 304/*!
417 Returns whether the document specified by \a f current exists 305 Returns whether the document specified by \a f current exists
418 as a file on disk. 306 as a file on disk.
419*/ 307*/
420bool FileManager::exists( const DocLnk &f ) 308bool FileManager::exists( const DocLnk &f )
421{ 309{
422 return QFile::exists(f.file()); 310 return QFile::exists(f.file());
423} 311}
424 312
425
426/*! 313/*!
427 Ensures that the path \a fn exists, by creating required directories. 314 Ensures that the path \a fn exists, by creating required directories.
428 Returns TRUE if successful. 315 Returns TRUE if successful.
429*/ 316*/
430bool FileManager::ensurePathExists( const QString &fn ) 317bool FileManager::ensurePathExists( const QString &fn )
431{ 318{
432 QFileInfo fi(fn); 319 QFileInfo fi(fn);
433 fi.setFile( fi.dirPath(TRUE) ); 320 fi.setFile( fi.dirPath(TRUE) );
434 if ( !fi.exists() ) { 321 if ( !fi.exists() )
435 if ( system(("mkdir -p "+fi.filePath())) ) 322 {
436 return FALSE; 323 if ( system(("mkdir -p "+fi.filePath())) )
324 return FALSE;
437 } 325 }
438 326
439 return TRUE; 327 return TRUE;
440} 328}