le_atomFile.h

Go to the documentation of this file.
1 /**
2  * @page c_atomFile Atomic File Operation API
3  *
4  * @subpage le_atomFile.h "API Reference"
5  *
6  * <HR>
7  *
8  * This API provides an atomic file access mechanism that can be used to perform file operation
9  * (specially file write) in atomic fashion.
10  *
11  * This API only supports regular files. Attempts to use this API on sockets, devices, etc. results
12  * in undefined behavior.
13  *
14  * @section c_atomFile_operation Atomic File Operations
15  *
16  * An atomic file operation is an operation that cannot be partially performed. Either the entire
17  * operation is performed or the operation fails. Any unclean reboot or power-cut should not lead to
18  * corruption or inconsistency of the file. Also when a process is performing an atomic write on a
19  * file, other processes should not be able modify that file, i.e. some file locking mechanism
20  * should be there.
21  *
22  * Use @c le_atomFile_Open() to open a file for atomic access. This API uses @ref c_flock_cooperative
23  * mechanism while opening a file, i.e. if file already has an incompatible lock on it,
24  * @c le_atomFile_Open() will block until it can obtain the lock. File must be closed using
25  * @c le_atomFile_Close() or @c le_atomFile_Cancel() api. Both @c le_atomFile_Close() and
26  * @c le_atomFile_Close() closes the file and releases the acquired resources. However,
27  * @c le_atomFile_Close() transfers all changes to disk, @c le_atomFile_Cancel() no change is
28  * reflected on file. A file can be deleted atomically using @c le_atomFile_Delete() api.
29  *
30  * For opening C standard file stream, please see @ref c_atomFile_streams section.
31  *
32  * Writing on the file descriptors obtained by this API same as writing to regular file descriptor.
33  * That means, any write to a file descriptor using this API doesn't ensure that data is transferred
34  * to disk. Data is only transferred to disk when le_atomFile_Close() returns successfully. This
35  * behavior is same for file stream as well.
36  *
37  * Code fragment illustrating atomic write using file descriptor.
38  *
39  * @code
40  *
41  * // Atomic write example, File Descriptor case.
42  *
43  * int fd = le_atomFile_Open("./myfile.txt", LE_FLOCK_READ_AND_APPEND);
44  *
45  * if (fd < 0)
46  * {
47  * // Print error message and exit.
48  * }
49  *
50  * // Write something in fd
51  * char myString[] = "This string for atomic writing";
52  *
53  * // Now write this string to fd
54  * write(fd, myString, sizeof(myString)); // This string write doesn't go disk
55  *
56  *
57  * le_result_t result = le_atomFile_Close(fd); // Transfers all changes to disk
58  *
59  * if (result == LE_OK)
60  * {
61  * // Print success message
62  * }
63  *
64  * @endcode
65  *
66  * Code fragment illustrating atomic write using file stream.
67  *
68  * @code
69  * // Atomic write example, File Stream case.
70  *
71  * FILE* file = le_atomFile_OpenStream("./myfile.txt", LE_FLOCK_READ_AND_APPEND, NULL);
72  *
73  * if (file == NULL)
74  * {
75  * // Print error message and exit.
76  * }
77  *
78  * // Write something in file stream
79  * char myString[] = "This string for atomic writing";
80  *
81  * // Now write this string to file stream
82  * fwrite(myString, 1, sizeof(myString), file); // This string write doesn't go disk
83  *
84  *
85  * le_result_t result = le_atomFile_CloseStream(fd); // Transfers all changes to disk
86  *
87  * if (result == LE_OK)
88  * {
89  * // Print success message
90  * }
91  *
92  * @endcode
93  *
94  * An example illustrating usage of le_atomFile_Close(), le_atomFile_Cancel() and
95  * le_atomFile_Delete() function.
96  *
97  * @code
98  *
99  * int fd = le_atomFile_Open("./myfile.txt", LE_FLOCK_READ_AND_APPEND);
100  *
101  * if (fd < 0)
102  * {
103  * // Print error message and exit.
104  * }
105  *
106  * // Write something in fd
107  * char myString[] = "This string for atomic writing";
108  *
109  * // Now write this string to fd
110  * write(fd, myString, sizeof(myString)); // This string write doesn't go disk
111  *
112  * bool doCommit = NeedToCommit(); // A fictitious function that returns whether
113  * // write on fd should be sent to disk or not.
114  *
115  * if (doCommit)
116  * {
117  * le_result_t result = le_atomFile_Close(fd); // Transfer all changes to disk and close
118  * // the file descriptor.
119  * if (result != LE_OK)
120  * {
121  * // Print error message.
122  * }
123  *
124  * }
125  * else
126  * {
127  * le_atomFile_Cancel(fd); // Discard all changes and close the file descriptor.
128  * }
129  *
130  *
131  * // Now do some additional stuff with file myfile.txt
132  * // .........Code.........
133  * // .........Code.........
134  *
135  *
136  * // Now delete file myfile.txt
137  * le_result_t result = le_atomFile_Delete("./myfile.txt");
138  * if (result != LE_OK)
139  * {
140  * // Print error message.
141  * }
142  *
143  * @endcode
144  *
145  * The le_atomFile_Create() function can be used to create, lock and open a file in one function
146  * call.
147  *
148  * @section c_atomFile_streams Streams
149  *
150  * The functions @c le_atomFile_OpenStream() and @c le_atomFile_CreateStream() can be used to obtain
151  * a file stream for atomic operation. @c le_atomFile_CloseStream() is used to commit all changes
152  * to disk and close the stream. @c le_atomFile_CancelStream() is used to discard all changes and
153  * close the stream. These functions are analogous to le_atomFile_Open(), le_atomFile_Create()
154  * le_atomFile_Close() and le_atomFile_Cancel() except that works on file streams rather than file
155  * descriptors.
156  *
157  * @section c_atomFile_nonblock Non-blocking
158  *
159  * Functions le_atomFile_Open(), le_atomFile_Create(), le_atomFile_OpenStream(),
160  * le_atomFile_CreateStream() and le_atomFile_Delete() always block if there is an incompatible lock
161  * on the file. Functions le_atomFile_TryOpen(), le_atomFile_TryCreate(),
162  * le_atomFile_TryOpenStream(), le_atomFile_TryCreateStream() and le_atomFile_TryDelete() are their
163  * non-blocking counterparts.
164  *
165  * @section c_atomFile_threading Multiple Threads
166  *
167  * All the functions in this API are thread-safe and reentrant.
168  *
169  * @section c_atomFile_limitations Limitations
170  *
171  * These APIs have inherent limitations of @ref c_flock (i.e. advisory lock, inability to detect
172  * deadlock etc.), as they use @ref c_flock.
173  *
174  * File descriptors obtained via calling these APIs can't be replicated via fork or dup
175  *
176  * @code
177  *
178  * int oldfd = le_atomFile_Open("./myfile.txt", LE_FLOCK_READ_AND_APPEND);
179  *
180  * if (oldfd < 0)
181  * {
182  * // Print error message and exit.
183  * }
184  *
185  * int newfd = dup(oldfd); // newfd is created via dup.
186  * ..
187  * // Write something in newfd
188  * ..
189  * le_result_t result = le_atomFile_Close(newfd); // Wrong. This newfd is not recognized by API
190  *
191  * @endcode
192  *
193  * File descriptors/streams obtained via using these APIs must be closed using the corresponding
194  * closing APIs (i.e. le_atomFile_Close(), le_atomFile_CloseStream() etc.). This is illustrated in
195  * following code fragments.
196  *
197  * Code fragment showing proper closing procedure of file descriptor obtained via this API.
198  *
199  * @code
200  *
201  * int fd = le_atomFile_Open("./myfile.txt", LE_FLOCK_READ_AND_APPEND);
202  *
203  * if (fd < 0)
204  * {
205  * // Print error message and exit.
206  * }
207  *
208  * ..
209  * // Write something in fd
210  * ..
211  * le_result_t result = le_atomFile_Close(fd); // This is right.
212  *
213  * if (result != LE_OK)
214  * {
215  * // Print some error message
216  * }
217  *
218  * @endcode
219  *
220  * Code fragment showing wrong closing procedure of file descriptor obtained via this API.
221  *
222  * @code
223  *
224  * int fd = le_atomFile_Open("./myfile.txt", LE_FLOCK_READ_AND_APPEND);
225  *
226  * if (fd < 0)
227  * {
228  * // Print error message and exit.
229  * }
230  *
231  * ..
232  * // Write something in fd
233  * ..
234  * int result = close(fd); // Wrong as it doesn't use closing API (i.e. le_atomFile_Close()
235  * // or le_atomFile_Cancel())
236  *
237  * if (result < 0)
238  * {
239  * // Print some error message
240  * }
241  *
242  * @endcode
243  *
244  * <HR>
245  *
246  * Copyright (C) Sierra Wireless Inc.
247  */
248 
249 //--------------------------------------------------------------------------------------------------
250 /** @file le_atomFile.h
251  *
252  * Legato @ref c_atomFile include file.
253  *
254  * Copyright (C) Sierra Wireless Inc.
255  */
256 
257 #ifndef LEGATO_ATOMFILE_INCLUDE_GUARD
258 #define LEGATO_ATOMFILE_INCLUDE_GUARD
259 
260 #include "le_fileLock.h"
261 
262 
263 //--------------------------------------------------------------------------------------------------
264 /**
265  * Opens an existing file for atomic access operation.
266  *
267  * The file can be open for reading, writing or both as specified in the accessMode argument.
268  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
269  * LE_FLOCK_READ and write lock will be placed for all other cases).
270  *
271  * This is a blocking call. It will block until it can open the target file with specified
272  * accessMode.
273  *
274  * @return
275  * A file descriptor if successful.
276  * LE_NOT_FOUND if the file does not exist.
277  * LE_FAULT if there was an error.
278  *
279  * @note
280  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
281  */
282 //--------------------------------------------------------------------------------------------------
284 (
285  const char* pathNamePtr, ///< [IN] Path of the file to open
286  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
287 );
288 
289 
290 //--------------------------------------------------------------------------------------------------
291 /**
292  * Creates and opens file for atomic operation.
293  *
294  * If the file does not exist it will be created with the file permissions specified in the argument
295  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
296  * of mode_t:
297  *
298  * http://man7.org/linux/man-pages/man2/open.2.html
299  *
300  * The file can be opened for reading, writing or both as specified in the accessMode argument.
301  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
302  * LE_FLOCK_READ and write lock will be placed for all other cases).
303  *
304  * This is a blocking call. It will block until it can create and open the target file with specified
305  * parameters(i.e. accessMode, createMode, permissions).
306  *
307  * @return
308  * A file descriptor if successful.
309  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
310  * LE_FAULT if there was an error.
311  *
312  * @note
313  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
314  */
315 //--------------------------------------------------------------------------------------------------
317 (
318  const char* pathNamePtr, ///< [IN] Path of the file to open
319  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
320  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
321  mode_t permissions ///< [IN] File permissions used when creating the file.
322  /// See the function header comments for more details.
323 );
324 
325 
326 //--------------------------------------------------------------------------------------------------
327 /**
328  * Same as @c le_atomFile_Open() except that it is non-blocking function and it will fail and return
329  * LE_WOULD_BLOCK immediately if target file has incompatible lock.
330  *
331  * @return
332  * A file descriptor if successful.
333  * LE_NOT_FOUND if the file does not exist.
334  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
335  * LE_FAULT if there was an error.
336  *
337  * @note
338  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
339  */
340 //--------------------------------------------------------------------------------------------------
342 (
343  const char* pathNamePtr, ///< [IN] Path of the file to open
344  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
345 );
346 
347 
348 //--------------------------------------------------------------------------------------------------
349 /**
350  * Same as @c le_atomFile_Create() except that it is non-blocking function and it will fail and
351  * return LE_WOULD_BLOCK immediately if target file has incompatible lock.
352  *
353  * @return
354  * A file descriptor if successful.
355  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
356  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
357  * LE_FAULT if there was an error.
358  *
359  * @note
360  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
361  */
362 //--------------------------------------------------------------------------------------------------
364 (
365  const char* pathNamePtr, ///< [IN] Path of the file to open
366  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
367  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
368  mode_t permissions ///< [IN] File permissions used when creating the file.
369 );
370 
371 
372 //--------------------------------------------------------------------------------------------------
373 /**
374  * Cancels all changes and closes the file descriptor.
375  */
376 //--------------------------------------------------------------------------------------------------
378 (
379  int fd /// [IN] The file descriptor to close.
380 );
381 
382 
383 //--------------------------------------------------------------------------------------------------
384 /**
385  * Commits all changes and closes the file descriptor. No need to close the file descriptor again if
386  * this function returns error (i.e. file descriptor is closed in both success and error scenario).
387  *
388  * @return
389  * LE_OK if successful.
390  * LE_FAULT if there was an error
391  */
392 //--------------------------------------------------------------------------------------------------
394 (
395  int fd /// [IN] The file descriptor to close.
396 );
397 
398 
399 //--------------------------------------------------------------------------------------------------
400 /**
401  * Opens an existing file via C standard library buffered file stream for atomic operation.
402  *
403  * The file can be open for reading, writing or both as specified in the accessMode argument.
404  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
405  * LE_FLOCK_READ and write lock will be placed for all other cases).
406  *
407  * This is a blocking call. It will block until it can open the target file with specified
408  * accessMode.
409  *
410  * If there was an error NULL is returned and resultPtr is set to:
411  * - LE_NOT_FOUND if the file does not exist.
412  * - LE_FAULT if there was an error.
413  *
414  * @return
415  * Buffered file stream handle to the file if successful.
416  * NULL if there was an error.
417  *
418  * @note
419  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
420  * function.
421  */
422 //--------------------------------------------------------------------------------------------------
424 (
425  const char* pathNamePtr, ///< [IN] Path of the file to open
426  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
427  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
428  /// the result code is not wanted.
429 );
430 
431 
432 //--------------------------------------------------------------------------------------------------
433 /**
434  * Creates and open a file via C standard library buffered file stream for atomic operation.
435  *
436  * If the file does not exist it will be created with the file permissions specified in the argument
437  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
438  * of mode_t:
439  *
440  * http://man7.org/linux/man-pages/man2/open.2.html
441  *
442  * The file can be opened for reading, writing or both as specified in the accessMode argument.
443  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
444  * LE_FLOCK_READ and write lock will be placed for all other cases).
445  *
446  * This is a blocking call. It will block until it can create and open the target file with
447  * specified parameters(i.e. accessMode, createMode, permissions).
448  *
449  * If there was an error NULL is returned and resultPtr is set to:
450  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
451  * - LE_FAULT if there was an error.
452  *
453  * @return
454  * Buffered file stream handle to the file if successful.
455  * NULL if there was an error.
456  *
457  * @note
458  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
459  * function.
460  */
461 //--------------------------------------------------------------------------------------------------
463 (
464  const char* pathNamePtr, ///< [IN] Path of the file to open
465  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
466  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
467  mode_t permissions, ///< [IN] File permissions used when creating the file.
468  /// See the function header comments for more details.
469  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
470  /// the result code is not wanted.
471 );
472 
473 
474 //--------------------------------------------------------------------------------------------------
475 /**
476  * Same as @c le_atomFile_OpenStream() except that it is non-blocking function and it will fail and
477  * return LE_WOULD_BLOCK immediately if target file has incompatible lock.
478  *
479  * If there was an error NULL is returned and resultPtr is set to:
480  * - LE_NOT_FOUND if the file does not exist.
481  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
482  * - LE_FAULT if there was an error.
483  *
484  * @return
485  * Buffered file stream handle to the file if successful.
486  * NULL if there was an error.
487  *
488  * @note
489  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
490  * function.
491  */
492 //--------------------------------------------------------------------------------------------------
494 (
495  const char* pathNamePtr, ///< [IN] Path of the file to open
496  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
497  le_result_t* resultPtr ///< [OUT] Pointer to result code.
498 );
499 
500 
501 //--------------------------------------------------------------------------------------------------
502 /**
503  * Same as @c le_atomFile_CreateStream() except that it is non-blocking function and it will fail
504  * and return LE_WOULD_BLOCK immediately if target file has incompatible lock.
505  *
506  * If there was an error NULL is returned and resultPtr is set to:
507  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
508  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
509  * - LE_FAULT if there was an error.
510  *
511  * @return
512  * Buffered file stream handle to the file if successful.
513  * NULL if there was an error.
514  *
515  * @note
516  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
517  * function.
518  */
519 //--------------------------------------------------------------------------------------------------
521 (
522  const char* pathNamePtr, ///< [IN] Path of the file to open
523  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
524  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
525  mode_t permissions, ///< [IN] File permissions used when creating the file.
526  le_result_t* resultPtr ///< [OUT] Pointer to result code.
527 );
528 
529 
530 //--------------------------------------------------------------------------------------------------
531 /**
532  * Cancels all changes and closes the file stream.
533  */
534 //--------------------------------------------------------------------------------------------------
536 (
537  FILE* fileStreamPtr ///< [IN] File stream pointer to close
538 );
539 
540 
541 //--------------------------------------------------------------------------------------------------
542 /**
543  * Commits all changes and closes the file stream. No need to close the file stream again if this
544  * function returns error (i.e. file stream is closed in both success and error scenario).
545  *
546  * @return
547  * LE_OK if successful.
548  * LE_FAULT if there was an error
549  */
550 //--------------------------------------------------------------------------------------------------
552 (
553  FILE* fileStreamPtr ///< [IN] File stream pointer to close
554 );
555 
556 
557 //--------------------------------------------------------------------------------------------------
558 /**
559  * Atomically deletes a file. This function also ensures safe deletion of file (i.e. if any other
560  * process/thread is using the file by acquiring file lock, it won't delete the file unless lock is
561  * released). This is a blocking call. It will block until lock on file is released.
562  *
563  * @return
564  * LE_OK if successful.
565  * LE_NOT_FOUND if file doesn't exists.
566  * LE_FAULT if there was an error.
567  */
568 //--------------------------------------------------------------------------------------------------
570 (
571  const char* pathNamePtr ///< [IN] Path of the file to delete
572 );
573 
574 
575 //--------------------------------------------------------------------------------------------------
576 /**
577  * Same as @c le_atomFile_Delete() except that it is non-blocking function and it will fail and
578  * return LE_WOULD_BLOCK immediately if target file is locked.
579  *
580  * @return
581  * LE_OK if successful.
582  * LE_NOT_FOUND if file doesn't exists.
583  * LE_WOULD_BLOCK if file is already locked (i.e. someone is using it).
584  * LE_FAULT if there was an error.
585  */
586 //--------------------------------------------------------------------------------------------------
588 (
589  const char* pathNamePtr ///< [IN] Path of the file to delete
590 );
591 
592 
593 #endif //LEGATO_ATOMIC_INCLUDE_GUARD
le_flock_AccessMode_t
Definition: le_fileLock.h:175
le_result_t le_atomFile_Delete(const char *pathNamePtr)
void le_atomFile_Cancel(int fd)
le_result_t
Definition: le_basics.h:45
int le_atomFile_TryCreate(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions)
int le_atomFile_Create(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions)
int le_atomFile_TryOpen(const char *pathNamePtr, le_flock_AccessMode_t accessMode)
FILE * le_atomFile_OpenStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_result_t *resultPtr)
le_result_t le_atomFile_CloseStream(FILE *fileStreamPtr)
FILE * le_atomFile_TryCreateStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions, le_result_t *resultPtr)
le_result_t le_atomFile_TryDelete(const char *pathNamePtr)
void le_atomFile_CancelStream(FILE *fileStreamPtr)
le_result_t le_atomFile_Close(int fd)
int le_atomFile_Open(const char *pathNamePtr, le_flock_AccessMode_t accessMode)
le_flock_CreateMode_t
Definition: le_fileLock.h:193
FILE * le_atomFile_TryOpenStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_result_t *resultPtr)
FILE * le_atomFile_CreateStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions, le_result_t *resultPtr)