libtdepim

tdefileio.cpp
1 // tdefileio.cpp
2 // Author: Stefan Taferner <taferner@kde.org>
3 // License: GPL
4 
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8 
9 #include <tdemessagebox.h>
10 #include <kdebug.h>
11 
12 #include <assert.h>
13 #include <tqdir.h>
14 
15 #include <tdelocale.h>
16 #include <kstdguiitem.h>
17 
18 #include <tqwidget.h>
19 #include <tqfile.h>
20 #include <tqfileinfo.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 
24 #include <tdemacros.h>
25 
26 namespace KPIM {
27 
28 //-----------------------------------------------------------------------------
29 static void msgDialog(const TQString &msg)
30 {
31  KMessageBox::sorry(0, msg, i18n("File I/O Error"));
32 }
33 
34 
35 //-----------------------------------------------------------------------------
36 TDE_EXPORT TQCString kFileToString(const TQString &aFileName, bool aEnsureNL, bool aVerbose)
37 {
38  TQCString result;
39  TQFileInfo info(aFileName);
40  unsigned int readLen;
41  unsigned int len = info.size();
42  TQFile file(aFileName);
43 
44  //assert(aFileName!=0);
45  if( aFileName.isEmpty() )
46  return "";
47 
48  if (!info.exists())
49  {
50  if (aVerbose)
51  msgDialog(i18n("The specified file does not exist:\n%1").arg(aFileName));
52  return TQCString();
53  }
54  if (info.isDir())
55  {
56  if (aVerbose)
57  msgDialog(i18n("This is a folder and not a file:\n%1").arg(aFileName));
58  return TQCString();
59  }
60  if (!info.isReadable())
61  {
62  if (aVerbose)
63  msgDialog(i18n("You do not have read permissions "
64  "to the file:\n%1").arg(aFileName));
65  return TQCString();
66  }
67  if (len <= 0) return TQCString();
68 
69  if (!file.open(IO_Raw|IO_ReadOnly))
70  {
71  if (aVerbose) switch(file.status())
72  {
73  case IO_ReadError:
74  msgDialog(i18n("Could not read file:\n%1").arg(aFileName));
75  break;
76  case IO_OpenError:
77  msgDialog(i18n("Could not open file:\n%1").arg(aFileName));
78  break;
79  default:
80  msgDialog(i18n("Error while reading file:\n%1").arg(aFileName));
81  }
82  return TQCString();
83  }
84 
85  result.resize(len + (int)aEnsureNL + 1);
86  readLen = file.readBlock(result.data(), len);
87  if (aEnsureNL && result[len-1]!='\n')
88  {
89  result[len++] = '\n';
90  readLen++;
91  }
92  result[len] = '\0';
93 
94  if (readLen < len)
95  {
96  TQString msg = i18n("Could only read %1 bytes of %2.")
97  .arg(readLen).arg(len);
98  msgDialog(msg);
99  return TQCString();
100  }
101 
102  return result;
103 }
104 
105 //-----------------------------------------------------------------------------
106 #if 0 // unused
107 TQByteArray kFileToBytes(const TQString &aFileName, bool aVerbose)
108 {
109  TQByteArray result;
110  TQFileInfo info(aFileName);
111  unsigned int readLen;
112  unsigned int len = info.size();
113  TQFile file(aFileName);
114 
115  //assert(aFileName!=0);
116  if( aFileName.isEmpty() )
117  return result;
118 
119  if (!info.exists())
120  {
121  if (aVerbose)
122  msgDialog(i18n("The specified file does not exist:\n%1")
123  .arg(aFileName));
124  return result;
125  }
126  if (info.isDir())
127  {
128  if (aVerbose)
129  msgDialog(i18n("This is a folder and not a file:\n%1")
130  .arg(aFileName));
131  return result;
132  }
133  if (!info.isReadable())
134  {
135  if (aVerbose)
136  msgDialog(i18n("You do not have read permissions "
137  "to the file:\n%1").arg(aFileName));
138  return result;
139  }
140  if (len <= 0) return result;
141 
142  if (!file.open(IO_Raw|IO_ReadOnly))
143  {
144  if (aVerbose) switch(file.status())
145  {
146  case IO_ReadError:
147  msgDialog(i18n("Could not read file:\n%1").arg(aFileName));
148  break;
149  case IO_OpenError:
150  msgDialog(i18n("Could not open file:\n%1").arg(aFileName));
151  break;
152  default:
153  msgDialog(i18n("Error while reading file:\n%1").arg(aFileName));
154  }
155  return result;
156  }
157 
158  result.resize(len);
159  readLen = file.readBlock(result.data(), len);
160  kdDebug(5300) << TQString( "len %1" ).arg(len) << endl;
161 
162  if (readLen < len)
163  {
164  TQString msg;
165  msg = i18n("Could only read %1 bytes of %2.")
166  .arg(readLen).arg(len);
167  msgDialog(msg);
168  return result;
169  }
170 
171  return result;
172 }
173 #endif
174 
175 //-----------------------------------------------------------------------------
176 TDE_EXPORT bool kBytesToFile(const char* aBuffer, int len,
177  const TQString &aFileName,
178  bool aAskIfExists, bool aBackup, bool aVerbose)
179 {
180  // TODO: use KSaveFile
181  TQFile file(aFileName);
182  int writeLen, rc;
183 
184  //assert(aFileName!=0);
185  if(aFileName.isEmpty())
186  return FALSE;
187 
188  if (file.exists())
189  {
190  if (aAskIfExists)
191  {
192  TQString str;
193  str = i18n("File %1 exists.\nDo you want to replace it?")
194  .arg(aFileName);
195  rc = KMessageBox::warningContinueCancel(0,
196  str, i18n("Save to File"), i18n("&Replace"));
197  if (rc != KMessageBox::Continue) return FALSE;
198  }
199  if (aBackup)
200  {
201  // make a backup copy
202  // TODO: use KSaveFile::backupFile()
203  TQString bakName = aFileName;
204  bakName += '~';
205  TQFile::remove(bakName);
206  if( !TQDir::current().rename(aFileName, bakName) )
207  {
208  // failed to rename file
209  if (!aVerbose) return FALSE;
210  rc = KMessageBox::warningContinueCancel(0,
211  i18n("Failed to make a backup copy of %1.\nContinue anyway?")
212  .arg(aFileName),
213  i18n("Save to File"), KStdGuiItem::save() );
214  if (rc != KMessageBox::Continue) return FALSE;
215  }
216  }
217  }
218 
219  if (!file.open(IO_Raw|IO_WriteOnly|IO_Truncate))
220  {
221  if (aVerbose) switch(file.status())
222  {
223  case IO_WriteError:
224  msgDialog(i18n("Could not write to file:\n%1").arg(aFileName));
225  break;
226  case IO_OpenError:
227  msgDialog(i18n("Could not open file for writing:\n%1")
228  .arg(aFileName));
229  break;
230  default:
231  msgDialog(i18n("Error while writing file:\n%1").arg(aFileName));
232  }
233  return FALSE;
234  }
235 
236  writeLen = file.writeBlock(aBuffer, len);
237 
238  if (writeLen < 0)
239  {
240  if (aVerbose)
241  msgDialog(i18n("Could not write to file:\n%1").arg(aFileName));
242  return FALSE;
243  }
244  else if (writeLen < len)
245  {
246  TQString msg = i18n("Could only write %1 bytes of %2.")
247  .arg(writeLen).arg(len);
248  if (aVerbose)
249  msgDialog(msg);
250  return FALSE;
251  }
252 
253  return TRUE;
254 }
255 
256 TDE_EXPORT bool kCStringToFile(const TQCString& aBuffer, const TQString &aFileName,
257  bool aAskIfExists, bool aBackup, bool aVerbose)
258 {
259  return kBytesToFile(aBuffer, aBuffer.length(), aFileName, aAskIfExists,
260  aBackup, aVerbose);
261 }
262 
263 TDE_EXPORT bool kByteArrayToFile(const TQByteArray& aBuffer, const TQString &aFileName,
264  bool aAskIfExists, bool aBackup, bool aVerbose)
265 {
266  return kBytesToFile(aBuffer, aBuffer.size(), aFileName, aAskIfExists,
267  aBackup, aVerbose);
268 }
269 
270 
271 TQString checkAndCorrectPermissionsIfPossible( const TQString &toCheck,
272  const bool recursive, const bool wantItReadable,
273  const bool wantItWritable )
274 {
275  // First we have to find out which type the toCheck is. This can be
276  // a directory (follow if recursive) or a file (check permissions).
277  // Symlinks are followed as expected.
278  TQFileInfo fiToCheck(toCheck);
279  fiToCheck.setCaching(false);
280  TQCString toCheckEnc = TQFile::encodeName(toCheck);
281  TQString error;
282  struct stat statbuffer;
283 
284  if ( !fiToCheck.exists() ) {
285  error.append( i18n("%1 does not exist")
286  .arg(toCheck) + "\n");
287  }
288 
289  // check the access bit of a folder.
290  if ( fiToCheck.isDir() ) {
291  if ( stat( toCheckEnc,&statbuffer ) != 0 ) {
292  kdDebug() << "wantItA: Can't read perms of " << toCheck << endl;
293  }
294  TQDir g( toCheck );
295  if ( !g.isReadable() ) {
296  if ( chmod( toCheckEnc, statbuffer.st_mode + S_IXUSR ) != 0 ) {
297  error.append( i18n("%1 is not accessible and that is "
298  "unchangeable.").arg(toCheck) + "\n");
299  } else {
300  kdDebug() << "Changed access bit for " << toCheck << endl;
301  }
302  }
303  }
304 
305  // For each file or folder we can check if the file is readable
306  // and writable, as requested.
307  if ( fiToCheck.isFile() || fiToCheck.isDir() ) {
308 
309  if ( !fiToCheck.isReadable() && wantItReadable ) {
310  // Get the current permissions. No need to do anything with an
311  // error, it will het added to errors anyhow, later on.
312  if ( stat(toCheckEnc,&statbuffer) != 0 ) {
313  kdDebug() << "wantItR: Can't read perms of " << toCheck << endl;
314  }
315 
316  // Lets try changing it.
317  if ( chmod( toCheckEnc, statbuffer.st_mode + S_IRUSR ) != 0 ) {
318  error.append( i18n("%1 is not readable and that is unchangeable.")
319  .arg(toCheck) + "\n");
320  } else {
321  kdDebug() << "Changed the read bit for " << toCheck << endl;
322  }
323  }
324 
325  if ( !fiToCheck.isWritable() && wantItWritable ) {
326  // Gets the current persmissions. Needed because it can be changed
327  // curing previous operation.
328  if (stat(toCheckEnc,&statbuffer) != 0) {
329  kdDebug() << "wantItW: Can't read perms of " << toCheck << endl;
330  }
331 
332  // Lets try changing it.
333  if ( chmod (toCheckEnc, statbuffer.st_mode + S_IWUSR ) != 0 ) {
334  error.append( i18n("%1 is not writable and that is unchangeable.")
335  .arg(toCheck) + "\n");
336  } else {
337  kdDebug() << "Changed the write bit for " << toCheck << endl;
338  }
339  }
340  }
341 
342  // If it is a folder and recursive is true, then we check the contents of
343  // the folder.
344  if ( fiToCheck.isDir() && recursive ){
345  TQDir g(toCheck);
346  // First check if the folder is readable for us. If not, we get
347  // some ugly crashes.
348  if ( !g.isReadable() ){
349  error.append(i18n("Folder %1 is inaccessible.").arg(toCheck) + "\n");
350  } else {
351  const TQFileInfoList *list = g.entryInfoList();
352  TQFileInfoListIterator it( *list );
353  TQFileInfo *fi;
354  while ((fi = it.current()) != 0) {
355  TQString newToCheck = toCheck + "/" + fi->fileName();
356  TQFileInfo fiNewToCheck(newToCheck);
357  if ( fi->fileName() != "." && fi->fileName() != ".." ) {
358  error.append ( checkAndCorrectPermissionsIfPossible( newToCheck,
359  recursive, wantItReadable, wantItWritable) );
360  }
361  ++it;
362  }
363  }
364  }
365  return error;
366 }
367 
369  const TQString &toCheck, const bool recursive, const bool wantItReadable,
370  const bool wantItWritable )
371 {
372  TQString error = checkAndCorrectPermissionsIfPossible(toCheck, recursive,
373  wantItReadable, wantItWritable);
374  // There is no KMessageBox with Retry, Cancel and Details.
375  // so, I can't provide a functionality to recheck. So it now
376  // it is just a warning.
377  if ( !error.isEmpty() ) {
378  kdDebug() << "checkPermissions found:" << error << endl;
379  KMessageBox::detailedSorry(parent,
380  i18n("Some files or folders do not have "
381  "the right permissions, please correct them "
382  "manually."),
383  error, i18n("Permissions Check"), false);
384  return false;
385  } else {
386  return true;
387  }
388 }
389 
390 }
TDEPIM classes for drag and drop of mails.
TDE_EXPORT bool kBytesToFile(const char *aBuffer, int len, const TQString &aFileName, bool aAskIfExists, bool aBackup, bool aVerbose)
Save a file.
Definition: tdefileio.cpp:176
TDE_EXPORT TQCString kFileToString(const TQString &aFileName, bool aEnsureNL, bool aVerbose)
Load a file.
Definition: tdefileio.cpp:36
TDE_EXPORT bool kByteArrayToFile(const TQByteArray &aBuffer, const TQString &aFileName, bool aAskIfExists, bool aBackup, bool aVerbose)
Does not stop at NUL.
Definition: tdefileio.cpp:263
bool checkAndCorrectPermissionsIfPossibleWithErrorHandling(TQWidget *parent, const TQString &toCheck, const bool recursive, const bool wantItReadable, const bool wantItWritable)
Checks and corrects the permissions of a file or folder, and if requested all files and folders below...
Definition: tdefileio.cpp:368
TQString checkAndCorrectPermissionsIfPossible(const TQString &toCheck, const bool recursive, const bool wantItReadable, const bool wantItWritable)
Checks and corrects the permissions of a file or folder, and if requested all files and folders below...
Definition: tdefileio.cpp:271