le_atomFile.h

Go to the documentation of this file.
1 /**
2  * @page c_atomFile Atomic File Operation API
3  *
4  * @ref 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 
261 //--------------------------------------------------------------------------------------------------
262 /**
263  * Opens an existing file for atomic access operation.
264  *
265  * The file can be open for reading, writing or both as specified in the accessMode argument.
266  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
267  * LE_FLOCK_READ and write lock will be placed for all other cases).
268  *
269  * This is a blocking call. It will block until it can open the target file with specified
270  * accessMode.
271  *
272  * @return
273  * A file descriptor if successful.
274  * LE_NOT_FOUND if the file does not exist.
275  * LE_FAULT if there was an error.
276  *
277  * @note
278  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
279  */
280 //--------------------------------------------------------------------------------------------------
282 (
283  const char* pathNamePtr, ///< [IN] Path of the file to open
284  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
285 );
286 
287 
288 //--------------------------------------------------------------------------------------------------
289 /**
290  * Creates and opens file for atomic operation.
291  *
292  * If the file does not exist it will be created with the file permissions specified in the argument
293  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
294  * of mode_t:
295  *
296  * http://man7.org/linux/man-pages/man2/open.2.html
297  *
298  * The file can be opened for reading, writing or both as specified in the accessMode argument.
299  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
300  * LE_FLOCK_READ and write lock will be placed for all other cases).
301  *
302  * This is a blocking call. It will block until it can create and open the target file with specified
303  * parameters(i.e. accessMode, createMode, permissions).
304  *
305  * @return
306  * A file descriptor if successful.
307  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
308  * LE_FAULT if there was an error.
309  *
310  * @note
311  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
312  */
313 //--------------------------------------------------------------------------------------------------
315 (
316  const char* pathNamePtr, ///< [IN] Path of the file to open
317  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
318  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
319  mode_t permissions ///< [IN] File permissions used when creating the file.
320  /// See the function header comments for more details.
321 );
322 
323 
324 //--------------------------------------------------------------------------------------------------
325 /**
326  * Same as @c le_atomFile_Open() except that it is non-blocking function and it will fail and return
327  * LE_WOULD_BLOCK immediately if target file has incompatible lock.
328  *
329  * @return
330  * A file descriptor if successful.
331  * LE_NOT_FOUND if the file does not exist.
332  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
333  * LE_FAULT if there was an error.
334  *
335  * @note
336  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
337  */
338 //--------------------------------------------------------------------------------------------------
340 (
341  const char* pathNamePtr, ///< [IN] Path of the file to open
342  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
343 );
344 
345 
346 //--------------------------------------------------------------------------------------------------
347 /**
348  * Same as @c le_atomFile_Create() except that it is non-blocking function and it will fail and
349  * return LE_WOULD_BLOCK immediately if target file has incompatible lock.
350  *
351  * @return
352  * A file descriptor if successful.
353  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
354  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
355  * LE_FAULT if there was an error.
356  *
357  * @note
358  * File must be closed using le_atomFile_Close() or le_atomFile_Cancel() function.
359  */
360 //--------------------------------------------------------------------------------------------------
362 (
363  const char* pathNamePtr, ///< [IN] Path of the file to open
364  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
365  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
366  mode_t permissions ///< [IN] File permissions used when creating the file.
367 );
368 
369 
370 //--------------------------------------------------------------------------------------------------
371 /**
372  * Cancels all changes and closes the file descriptor.
373  */
374 //--------------------------------------------------------------------------------------------------
376 (
377  int fd /// [IN] The file descriptor to close.
378 );
379 
380 
381 //--------------------------------------------------------------------------------------------------
382 /**
383  * Commits all changes and closes the file descriptor. No need to close the file descriptor again if
384  * this function returns error (i.e. file descriptor is closed in both success and error scenario).
385  *
386  * @return
387  * LE_OK if successful.
388  * LE_FAULT if there was an error
389  */
390 //--------------------------------------------------------------------------------------------------
392 (
393  int fd /// [IN] The file descriptor to close.
394 );
395 
396 
397 //--------------------------------------------------------------------------------------------------
398 /**
399  * Opens an existing file via C standard library buffered file stream for atomic operation.
400  *
401  * The file can be open for reading, writing or both as specified in the accessMode argument.
402  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
403  * LE_FLOCK_READ and write lock will be placed for all other cases).
404  *
405  * This is a blocking call. It will block until it can open the target file with specified
406  * accessMode.
407  *
408  * If there was an error NULL is returned and resultPtr is set to:
409  * - LE_NOT_FOUND if the file does not exist.
410  * - LE_FAULT if there was an error.
411  *
412  * @return
413  * Buffered file stream handle to the file if successful.
414  * NULL if there was an error.
415  *
416  * @note
417  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
418  * function.
419  */
420 //--------------------------------------------------------------------------------------------------
422 (
423  const char* pathNamePtr, ///< [IN] Path of the file to open
424  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
425  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
426  /// the result code is not wanted.
427 );
428 
429 
430 //--------------------------------------------------------------------------------------------------
431 /**
432  * Creates and open a file via C standard library buffered file stream for atomic operation.
433  *
434  * If the file does not exist it will be created with the file permissions specified in the argument
435  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
436  * of mode_t:
437  *
438  * http://man7.org/linux/man-pages/man2/open.2.html
439  *
440  * The file can be opened for reading, writing or both as specified in the accessMode argument.
441  * Parameter accessMode specifies the lock to be applied on the file (read lock will be applied for
442  * LE_FLOCK_READ and write lock will be placed for all other cases).
443  *
444  * This is a blocking call. It will block until it can create and open the target file with
445  * specified parameters(i.e. accessMode, createMode, permissions).
446  *
447  * If there was an error NULL is returned and resultPtr is set to:
448  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
449  * - LE_FAULT if there was an error.
450  *
451  * @return
452  * Buffered file stream handle to the file if successful.
453  * NULL if there was an error.
454  *
455  * @note
456  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
457  * function.
458  */
459 //--------------------------------------------------------------------------------------------------
461 (
462  const char* pathNamePtr, ///< [IN] Path of the file to open
463  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
464  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
465  mode_t permissions, ///< [IN] File permissions used when creating the file.
466  /// See the function header comments for more details.
467  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
468  /// the result code is not wanted.
469 );
470 
471 
472 //--------------------------------------------------------------------------------------------------
473 /**
474  * Same as @c le_atomFile_OpenStream() except that it is non-blocking function and it will fail and
475  * return LE_WOULD_BLOCK immediately if target file has incompatible lock.
476  *
477  * If there was an error NULL is returned and resultPtr is set to:
478  * - LE_NOT_FOUND if the file does not exist.
479  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
480  * - LE_FAULT if there was an error.
481  *
482  * @return
483  * Buffered file stream handle to the file if successful.
484  * NULL if there was an error.
485  *
486  * @note
487  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
488  * function.
489  */
490 //--------------------------------------------------------------------------------------------------
492 (
493  const char* pathNamePtr, ///< [IN] Path of the file to open
494  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
495  le_result_t* resultPtr ///< [OUT] Pointer to result code.
496 );
497 
498 
499 //--------------------------------------------------------------------------------------------------
500 /**
501  * Same as @c le_atomFile_CreateStream() except that it is non-blocking function and it will fail
502  * and return LE_WOULD_BLOCK immediately if target file has incompatible lock.
503  *
504  * If there was an error NULL is returned and resultPtr is set to:
505  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
506  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
507  * - LE_FAULT if there was an error.
508  *
509  * @return
510  * Buffered file stream handle to the file if successful.
511  * NULL if there was an error.
512  *
513  * @note
514  * Stream must be closed using le_atomFile_CloseStream() or le_atomFile_CancelStream()
515  * function.
516  */
517 //--------------------------------------------------------------------------------------------------
519 (
520  const char* pathNamePtr, ///< [IN] Path of the file to open
521  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
522  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
523  mode_t permissions, ///< [IN] File permissions used when creating the file.
524  le_result_t* resultPtr ///< [OUT] Pointer to result code.
525 );
526 
527 
528 //--------------------------------------------------------------------------------------------------
529 /**
530  * Cancels all changes and closes the file stream.
531  */
532 //--------------------------------------------------------------------------------------------------
534 (
535  FILE* fileStreamPtr ///< [IN] File stream pointer to close
536 );
537 
538 
539 //--------------------------------------------------------------------------------------------------
540 /**
541  * Commits all changes and closes the file stream. No need to close the file stream again if this
542  * function returns error (i.e. file stream is closed in both success and error scenario).
543  *
544  * @return
545  * LE_OK if successful.
546  * LE_FAULT if there was an error
547  */
548 //--------------------------------------------------------------------------------------------------
550 (
551  FILE* fileStreamPtr ///< [IN] File stream pointer to close
552 );
553 
554 
555 //--------------------------------------------------------------------------------------------------
556 /**
557  * Atomically deletes a file. This function also ensures safe deletion of file (i.e. if any other
558  * process/thread is using the file by acquiring file lock, it won't delete the file unless lock is
559  * released). This is a blocking call. It will block until lock on file is released.
560  *
561  * @return
562  * LE_OK if successful.
563  * LE_NOT_FOUND if file doesn't exists.
564  * LE_FAULT if there was an error.
565  */
566 //--------------------------------------------------------------------------------------------------
568 (
569  const char* pathNamePtr ///< [IN] Path of the file to delete
570 );
571 
572 
573 //--------------------------------------------------------------------------------------------------
574 /**
575  * Same as @c le_atomFile_Delete() except that it is non-blocking function and it will fail and
576  * return LE_WOULD_BLOCK immediately if target file is locked.
577  *
578  * @return
579  * LE_OK if successful.
580  * LE_NOT_FOUND if file doesn't exists.
581  * LE_WOULD_BLOCK if file is already locked (i.e. someone is using it).
582  * LE_FAULT if there was an error.
583  */
584 //--------------------------------------------------------------------------------------------------
586 (
587  const char* pathNamePtr ///< [IN] Path of the file to delete
588 );
589 
590 
591 #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:35
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)