1/* kate: tab-indents off; replace-tabs on; tab-width 4; remove-trailing-space on; encoding utf-8;*/
2/*
3 This file is part of the KDE libraries
4 Copyright 1999 Waldo Bastian <bastian@kde.org>
5 Copyright 2006 Jaison Lee <lee.jaison@gmail.com>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License version 2 as published by the Free Software Foundation.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#ifndef KSAVEFILE_H
23#define KSAVEFILE_H
24
25#include <kdecore_export.h>
26
27#include <QtCore/QFile>
28#include <QtCore/QString>
29#include <kglobal.h>
30
31/**
32 * \class KSaveFile ksavefile.h <KSaveFile>
33 *
34 * @brief Class to allow for atomic file I/O, as well as utility functions.
35 *
36 * The KSaveFile class has been made to write out changes to an existing
37 * file atomically. This means that either <b>ALL</b> changes will be written
38 * to the file, or <b>NO</b> changes have been written, and the original file
39 * (if any) has been unchanged. This is useful if you have lots of
40 * time-consuming processing to perform during which an interruption could
41 * occur, or if any error in the file structure will cause the entire file
42 * to be corrupt.
43 *
44 * When you create a KSaveFile for a given file, a temporary file is instead
45 * created and all your I/O occurs in the save file. Once you call finalize()
46 * the temporary file is renamed to the target file, so that all your changes
47 * happen at once. If abort() is called then the temporary file is removed and
48 * the target file is untouched. KSaveFile derives from QFile so you can use
49 * it just as you would a normal QFile.
50 *
51 * This class also includes several static utility functions available that
52 * can help ensure data integrity. See the individual functions for details.
53 *
54 * Here is a quick example of how to use KSaveFile:
55 *
56 * First we create the KSaveFile and open it.
57 *
58 * @code
59 * KSaveFile saveFile;
60 * saveFile.setFileName("/lib/foo/bar.dat");
61 * if ( !saveFile.open() ) {
62 * //Handle error
63 * }
64 * @endcode
65 *
66 * At this point the file "/lib/foo/bar.dat" has not been altered in any way.
67 * Now, let's write out some data to the file.
68 *
69 * @code
70 * QTextStream stream ( &saveFile );
71 * stream << "Add some data.";
72 * // Perform long processing
73 * stream << "Add some more data.";
74 * stream.flush();
75 * @endcode
76 *
77 * Even after writing this data, the target file "/lib/foo/bar.dat" still has
78 * not been altered in any way. Now that we are done writing our data, we can
79 * write out all the changes that we have made by calling finalize().
80 *
81 * @code
82 * if ( !saveFile.finalize() ) {
83 * //Handle error
84 * }
85 * @endcode
86 *
87 * If a user interruption or error occurred while we were writing out our
88 * changes, we would instead call abort() to cancel all the I/O without
89 * affecting the target file.
90 *
91 * @see QFile
92 *
93 * @author Jaison Lee <lee.jaison@gmail.com>
94 * @author Waldo Bastian <bastian@kde.org>
95 */
96class KDECORE_EXPORT KSaveFile : public QFile
97{
98public:
99 /**
100 * Default constructor.
101 */
102 KSaveFile();
103
104 /**
105 * Creates a new KSaveFile and sets the target file to @p filename.
106 *
107 * @param filename the path of the file
108 * @param componentData unused
109 */
110 explicit KSaveFile(const QString &filename, const KComponentData &componentData = KGlobal::mainComponent()); // KDE5 TODO: remove KComponentData
111
112 /**
113 * Destructor.
114 * @note If the file has been opened but not yet finalized, the
115 * destructor will call finalize(). If you do not want the target file
116 * to be affected you need to call abort() before destroying the object.
117 **/
118 virtual ~KSaveFile();
119
120 /**
121 * @brief Set the target filename for the save file.
122 * You must use this to set the filename of the target file if you do
123 * not use the contructor that does so.
124 * @param filename Name of the target file.
125 */
126 void setFileName(const QString &filename);
127
128 /**
129 * @brief Returns the name of the target file.
130 * This function returns the name of the target file, or an empty
131 * QString if it has not yet been set.
132 * @returns The name of the target file.
133 */
134 QString fileName() const;
135
136 /**
137 * @brief Returns the last error that occurred.
138 * Use this function to check for errors.
139 * @returns The last error that occurred, or QFile::NoError.
140 */
141 QFile::FileError error() const;
142
143 /**
144 * @brief Returns a human-readable description of the last error.
145 * Use this function to get a human-readable description of the
146 * last error that occurred.
147 * @return A string describing the last error that occurred.
148 */
149 QString errorString() const;
150
151 /**
152 * @brief Open the save file.
153 * This function will open the save file by creating a temporary file to write
154 * to. It will also check to ensure that there are sufficient permissions to
155 * write to the target file.
156 *
157 * @param flags Sets the QIODevice::OpenMode. It should contain the write flag, otherwise you
158 * have a save file you cannot save to.
159 *
160 * @return true if successful, or false if an error has occurred.
161 */
162 virtual bool open(OpenMode flags = QIODevice::ReadWrite);
163
164 /**
165 * @brief Discard changes without affecting the target file.
166 * This will discard all changes that have been made to this file.
167 * The target file will not be altered in any way.
168 **/
169 void abort();
170
171 /**
172 * @brief Finalize changes to the file.
173 * This will commit all the changes that have been made to the file.
174 * @return true if successful, or false if an error has occurred.
175 **/
176 bool finalize();
177
178 /**
179 * Allows writing over the existing file if necessary.
180 *
181 * QSaveFile creates a temporary file in the same directory as the final
182 * file and atomically renames it. However this is not possible if the
183 * directory permissions do not allow creating new files.
184 * In order to preserve atomicity guarantees, open() fails when it
185 * cannot create the temporary file.
186 *
187 * In order to allow users to edit files with write permissions in a
188 * directory with restricted permissions, call setDirectWriteFallback() with
189 * \a enabled set to true, and the following calls to open() will fallback to
190 * opening the existing file directly and writing into it, without the use of
191 * a temporary file.
192 * This does not have atomicity guarantees, i.e. an application crash or
193 * for instance a power failure could lead to a partially-written file on disk.
194 * It also means cancelWriting() has no effect, in such a case.
195 *
196 * Typically, to save documents edited by the user, call setDirectWriteFallback(true),
197 * and to save application internal files (configuration files, data files, ...), keep
198 * the default setting which ensures atomicity.
199 *
200 * @since 4.10.3
201 */
202 void setDirectWriteFallback(bool enabled);
203
204 /**
205 * Returns true if the fallback solution for saving files in read-only
206 * directories is enabled.
207 *
208 * @since 4.10.3
209 */
210 bool directWriteFallback() const;
211
212 /**
213 * @brief Static method to create a backup file before saving.
214 *
215 * If empty (the default), the backup will be in the same directory as @p filename.
216 * The backup type (simple, rcs, or numbered), extension string, and maximum
217 * number of backup files are read from the user's global configuration.
218 * Use simpleBackupFile() or numberedBackupFile() to force one of these
219 * specific backup styles.
220 * You can use this method even if you don't use KSaveFile.
221 * @param filename the file to backup
222 * @param backupDir optional directory where to save the backup file in.
223 * @return true if successful, or false if an error has occurred.
224 */
225 static bool backupFile( const QString& filename,
226 const QString& backupDir = QString() );
227
228 /**
229 * @brief Static method to create a backup file for a given filename.
230 *
231 * This function creates a backup file from the given filename.
232 * You can use this method even if you don't use KSaveFile.
233 * @param filename the file to backup
234 * @param backupDir optional directory where to save the backup file in.
235 * If empty (the default), the backup will be in the same directory as @p filename.
236 * @param backupExtension the extension to append to @p filename, "~" by default.
237 * @return true if successful, or false if an error has occurred.
238 */
239 static bool simpleBackupFile( const QString& filename,
240 const QString& backupDir = QString(),
241 const QString& backupExtension = QLatin1String( "~" ) );
242
243 /**
244 * @brief Static method to create a backup file for a given filename.
245 *
246 * This function creates a series of numbered backup files from the
247 * given filename.
248 *
249 * The backup file names will be of the form:
250 * \<name\>.\<number\>\<extension\>
251 * for instance
252 * \verbatim chat.3.log \endverbatim
253 *
254 * The new backup file will be have the backup number 1.
255 * Each existing backup file will have its number incremented by 1.
256 * Any backup files with numbers greater than the maximum number
257 * permitted (@p maxBackups) will be removed.
258 * You can use this method even if you don't use KSaveFile.
259 *
260 * @param filename the file to backup
261 * @param backupDir optional directory where to save the backup file in.
262 * If empty (the default), the backup will be in the same directory as
263 * @p filename.
264 * @param backupExtension the extension to append to @p filename,
265 * which is "~" by default. Do not use an extension containing digits.
266 * @param maxBackups the maximum number of backup files permitted.
267 * For best performance a small number (10) is recommended.
268 * @return true if successful, or false if an error has occurred.
269 */
270 static bool numberedBackupFile( const QString& filename,
271 const QString& backupDir = QString(),
272 const QString& backupExtension = QString::fromLatin1( "~" ),
273 const uint maxBackups = 10
274 );
275
276
277 /**
278 * @brief Static method to create an rcs backup file for a given filename.
279 *
280 * This function creates a rcs-formatted backup file from the
281 * given filename.
282 *
283 * The backup file names will be of the form:
284 * \<name\>,v
285 * for instance
286 * \verbatim photo.jpg,v \endverbatim
287 *
288 * The new backup file will be in RCS format.
289 * Each existing backup file will be committed as a new revision.
290 * You can use this method even if you don't use KSaveFile.
291 *
292 * @param filename the file to backup
293 * @param backupDir optional directory where to save the backup file in.
294 * If empty (the default), the backup will be in the same directory as
295 * @p filename.
296 * @param backupMessage is the RCS commit message for this revision.
297 * @return true if successful, or false if an error has occurred.
298 */
299 static bool rcsBackupFile( const QString& filename,
300 const QString& backupDir = QString(),
301 const QString& backupMessage = QString()
302 );
303
304private:
305 Q_DISABLE_COPY(KSaveFile)
306
307 class Private;
308 Private *const d;
309};
310
311#endif
312