le_fileLock.h

Go to the documentation of this file.
1 /**
2  * @page c_flock File Locking API
3  *
4  * @ref le_fileLock.h "API Reference"
5  *
6  * <HR>
7  *
8  * File locking is a form of IPC used to synchronize multiple processes' access to
9  * common files.
10  *
11  * This API provides a co-operative file locking mechanism that can be used by multiple processes
12  * and/or threads to sychronize reads and writes to common files.
13  *
14  * This API only supports regular files. Attempts to use this API on sockets, devices, etc. results
15  * in undefined behaviour.
16  *
17  * @section c_flock_cooperative Co-operative File Locking
18  *
19  * Co-operative file locks (also known as advisory file locks) means that the processes and threads
20  * must co-operate to synchronize their access to the file. If a process or thread simply ignores
21  * the lock and accesses the file then access synchronization errors may occur.
22  *
23  * @section c_flock_locks Locking Files
24  *
25  * There are two types of locks that can be applied: read lock and write lock. A file
26  * can have multiple simultaneous read locks, but can only have one write lock. Also, a
27  * file can only have one type of lock on it at one time. A file may be locked
28  * for reading if the file is unlocked or if there are read locks on the file, but to lock a file
29  * for writing the file must be unlocked.
30  *
31  * Use @c le_flock_Open() to lock a file and open it for access. When attempting to lock a file that
32  * already has an incompatible lock on it, @c le_flock_Open() will block until it can obtain the lock.
33  * Call @c le_flock_Close() to close the file and remove the lock on the file.
34  *
35  * This code sample shows four processes attempting to access the same file. Assume
36  * that all the calls to le_flock_Open() in the example occur in chronological order as they appear:
37  *
38  * @code
39  * // Code in Process 1.
40  *
41  * // Lock the file for reading.
42  * int fd = le_flock_Open("foo", LE_FLOCK_READ); // This call will not block.
43  *
44  * // Read from the file.
45  * ...
46  *
47  * // Close the file and release the lock.
48  * le_flock_Close(fd);
49  * -------------------------------------------------------------------------------------------------
50  *
51  * // Code in Process 2.
52  *
53  * // Lock the file for reading.
54  * int fd = le_flock_Open("foo", LE_FLOCK_READ); // This call will not block.
55  *
56  * // Read from the file.
57  * ...
58  *
59  * // Close the file and release the lock.
60  * le_flock_Close(fd);
61  * -------------------------------------------------------------------------------------------------
62  *
63  * // Code in Process 3.
64  *
65  * // Lock the file for writing.
66  * int fd = le_flock_Open("foo", LE_FLOCK_WRITE); // This call will block until both Process 1
67  * // and Process 2 removes their locks.
68  *
69  * // Write to the file.
70  * ...
71  *
72  * // Close the file and release the lock.
73  * le_flock_Close(fd);
74  * @endcode
75  *
76  * This sample shows that Process 2 obtains the read lock even though Process 1 already
77  * has a read lock on the file. Process 3 is blocked because it's attempting a
78  * write lock on the file. Process 3 is blocked until both Process 1 and 2 remove their locks.
79  *
80  * When multiple processes are blocked waiting to obtain a lock on the file, it's unspecified which
81  * process will obtain the lock when the file becomes available.
82  *
83  * The le_flock_Create() function can be used to create, lock and open a file in one function call.
84  *
85  * @section c_flock_streams Streams
86  *
87  * The functions @c le_flock_OpenStream() and @c le_flock_CreateStream() can be used to obtain a file
88  * stream to a locked file. @c le_flock_CloseStream() is used to close the stream and remove the lock.
89  * These functions are analogous to le_flock_Open(), le_flock_Create() and le_flock_Close() except
90  * that they return file streams rather than file descriptors.
91  *
92  * @section c_flock_nonblock Non-blocking
93  *
94  * Functions le_flock_Open(), le_flock_Create(), le_flock_OpenStream() and
95  * le_flock_CreateStream() always block if there is an incompatible lock on the file. Functions
96  * le_flock_TryOpen(), le_flock_TryCreate(), le_flock_TryOpenStream() and
97  * le_flock_TryCreateStream() are their non-blocking counterparts.
98  *
99  * @section c_flock_threads Multiple Threads
100  *
101  * All functions in this API are thread-safe; processes and threads can use this API to
102  * synchronize their access to files.
103  *
104  * @section c_flock_replicateFd Replicating File Descriptors
105  *
106  * File locks are contained in the file descriptors that are returned by le_flock_Open() and
107  * le_flock_Create() and in the underlying file descriptors of the file streams returned by
108  * le_flock_OpenStream() and le_flock_CreateStream().
109  *
110  * File descriptors are closed the locks are automatically removed. Functions
111  * le_flock_Close() and le_flock_CloseStream() are provided as a convenience. When a process dies,
112  * all of its file descriptors are closed and any file locks they may contain are removed.
113  *
114  * If a file descriptor is replicated either through dup() or fork(), the file lock will also be
115  * replicated in the new file descriptor:
116  *
117  * @code
118  * int oldfd = le_flock_Open("foo", LE_FLOCK_READ); // Place a read lock on the file "foo".
119  * int newfd = dup(oldfd);
120  *
121  * le_flock_Close(oldfd); // Closes the fd and removes the lock.
122  * @endcode
123  *
124  * There must still be a read lock on the file "foo" because newfd
125  * has not been closed.
126  *
127  * This behaviour can be used to pass file locks from a parent to a child through a fork() call.
128  * The parent can obtain the file lock, fork() and close its file descriptor. Now the child has
129  * exclusive possession of the file lock.
130  *
131  * @section c_flock_limitations Limitations
132  *
133  * Here are some limitations to the file locking mechanisms in this API:
134  *
135  * The file locks in this API are advisory only, meaning that a process may
136  * simply ignore the lock and access the file anyways.
137  *
138  * This API does not detect deadlocks and a process may deadlock itself. For example:
139  *
140  * @code
141  * int fd1 = le_flock_Open("foo", LE_FLOCK_READ); // Obtains a read lock on the file.
142  * int fd2 = le_flock_Open("foo", LE_FLOCK_WRITE); // This call will block forever.
143  * @endcode
144  *
145  * This API only permits whole files to be locked, not portions of a
146  * file.
147  *
148  * Many NFS implementations don't recognize locks used by this API.
149  *
150  * <HR>
151  *
152  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
153  */
154 
155  //--------------------------------------------------------------------------------------------------
156 /** @file le_fileLock.h
157  *
158  * Legato @ref c_flock include file.
159  *
160  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
161  */
162 
163 #ifndef LEGATO_FLOCK_INCLUDE_GUARD
164 #define LEGATO_FLOCK_INCLUDE_GUARD
165 
166 
167 //--------------------------------------------------------------------------------------------------
168 /**
169  * File access modes.
170  *
171  * @note When writing to a file, the writes are always appended to the end of the file by default.
172  * When reading from a file, the reads always starts at the beginning of the file by default.
173  */
174 //--------------------------------------------------------------------------------------------------
175 typedef enum
176 {
177  LE_FLOCK_READ, ///< Opens the file for reading.
178  LE_FLOCK_WRITE, ///< Opens the file for writing.
179  LE_FLOCK_APPEND, ///< Opens the file for writing. Writes will be appended to the end
180  /// of the file.
181  LE_FLOCK_READ_AND_WRITE, ///< Opens the file for reading and writing.
182  LE_FLOCK_READ_AND_APPEND ///< Opens the file for reading and writing. Writes will be
183  /// appended to the end of the file.
184 }
186 
187 
188 //--------------------------------------------------------------------------------------------------
189 /**
190  * File creation modes specify the action to take when creating a file that already exists.
191  */
192 //--------------------------------------------------------------------------------------------------
193 typedef enum
194 {
195  LE_FLOCK_OPEN_IF_EXIST, ///< Opens the file if it already exists.
196  LE_FLOCK_REPLACE_IF_EXIST, ///< Replaces the file if it already exists.
197  LE_FLOCK_FAIL_IF_EXIST ///< Fails if the file already exists.
198 }
200 
201 
202 //--------------------------------------------------------------------------------------------------
203 /**
204  * Opens and locks an existing file.
205  *
206  * The file can be open for reading, writing or both as specified in the accessMode argument. If
207  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE then a write lock will be placed
208  * on the file, otherwise a read lock will be placed on the file.
209  *
210  * If attempting to lock a file that already has an incompatible lock on it this function will block
211  * until the lock can be obtained.
212  *
213  * @return
214  * File descriptor to the file specified in pathNamePtr.
215  * LE_NOT_FOUND if the file does not exist.
216  * LE_FAULT if there was an error.
217  */
218 //--------------------------------------------------------------------------------------------------
219 int le_flock_Open
220 (
221  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
222  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
223 );
224 
225 
226 //--------------------------------------------------------------------------------------------------
227 /**
228  * Creates, opens and locks file.
229  *
230  * If the file does not exist, it will be created with the file permissions specified in the arugment
231  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
232  * of mode_t:
233  *
234  * http://man7.org/linux/man-pages/man2/open.2.html
235  *
236  * If the file already exists, then this function will either replace the existing file, open the
237  * existing file or fail depending on the createMode argument. The permissions argument is ignored
238  * if the file already exists.
239  *
240  * The file can be opened for reading, writing or both as specified in the accessMode argument. If
241  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE, a write lock will be placed
242  * on the file, otherwise a read lock will be placed on the file.
243  *
244  * If attempting to lock a file that already has an incompatible lock on it, this function will block
245  * until the lock can be obtained. This function may block even if it creates the file because
246  * creating the file and locking it is not atomic.
247  *
248  * @return
249  * File descriptor to the file specified in pathNamePtr.
250  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
251  * LE_FAULT if there was an error.
252  */
253 //--------------------------------------------------------------------------------------------------
254 int le_flock_Create
255 (
256  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
257  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
258  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
259  mode_t permissions ///< [IN] File permissions used when creating the file.
260  /// See the function header comments for more details.
261 );
262 
263 
264 //--------------------------------------------------------------------------------------------------
265 /**
266  * Opens and locks an existing file.
267  *
268  * The file can be open for reading, writing or both as specified in the accessMode argument. If
269  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE, a write lock will be placed
270  * on the file, otherwise a read lock will be placed on the file.
271  *
272  * If attempting to lock a file that already has an incompatible lock on it, this function will fail
273  * and return LE_WOULD_BLOCK immediately.
274  *
275  * @return
276  * File descriptor to the file specified in pathNamePtr.
277  * LE_NOT_FOUND if the file does not exist.
278  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
279  * LE_FAULT if there was an error.
280  */
281 //--------------------------------------------------------------------------------------------------
283 (
284  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
285  le_flock_AccessMode_t accessMode ///< [IN] Access mode to open the file.
286 );
287 
288 
289 //--------------------------------------------------------------------------------------------------
290 /**
291  * Creates, opens and locks file.
292  *
293 * If the file does not exist, it will be created with the file permissions specified in the argument
294  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
295  * of mode_t:
296  *
297  * http://man7.org/linux/man-pages/man2/open.2.html
298  *
299  * If the file already exists, this function will either replace the existing file, open the
300  * existing file or fail depending on the createMode argument. The permissions argument is ignored
301  * if the file already exists.
302  *
303  * The file can be opened for reading, writing or both as specified in the accessMode argument. f
304  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE, a write lock will be placed
305  * on the file, otherwise a read lock will be placed on the file.
306  *
307  * If attempting to lock a file that already has an incompatible lock on it, this function will fail
308  * and return LE_WOULD_BLOCK immediately. This function may fail with LE_WOULD_BLOCK even if it
309  * creates the file because creating the file and locking it is not atomic.
310  *
311  * @return
312  * File descriptor to the file specified in pathNamePtr.
313  * LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode
314  * LE_WOULD_BLOCK if there is already an incompatible lock on the file.
315  * LE_FAULT if there was an error.
316  */
317 //--------------------------------------------------------------------------------------------------
319 (
320  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
321  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
322  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
323  mode_t permissions ///< [IN] File permissions used when creating the file.
324  /// See the function header comments for more details.
325 );
326 
327 
328 //--------------------------------------------------------------------------------------------------
329 /**
330  * Closes the file and releases the lock.
331  */
332 //--------------------------------------------------------------------------------------------------
333 void le_flock_Close
334 (
335  int fd ///< [IN] File descriptor of the file to close.
336 );
337 
338 
339 //--------------------------------------------------------------------------------------------------
340 /**
341  * Locks an existing file and opens a C standard library buffered file stream to it.
342  *
343  * The file can be open for reading, writing or both read and write as specified in the accessMode
344  * argument. If accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE then a write lock
345  * will be placed on the file, otherwise a read lock will be placed on the file.
346  *
347  * If attempting to lock a file that already has an incompatible lock on it, this function will block
348  * until the lock can be obtained.
349  *
350  * If there was an error NULL is returned and resultPtr is set to:
351  * - LE_NOT_FOUND if the file does not exist.
352  * - LE_FAULT if there was an error.
353  *
354  * @return
355  * Buffered file stream handle to the file if successful.
356  * NULL if there was an error.
357  */
358 //--------------------------------------------------------------------------------------------------
360 (
361  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
362  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
363  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
364  /// the result code is not wanted.
365 );
366 
367 
368 //--------------------------------------------------------------------------------------------------
369 /**
370  * Creates a file, locks it and opens a C standard library buffered file stream to it.
371  *
372  * If the file does not exist it will be created with the file permissions specified in the arugment
373  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
374  * of mode_t:
375  *
376  * http://man7.org/linux/man-pages/man2/open.2.html
377  *
378  * If the file already exists then this function will either replace the existing file, open the
379  * existing file or fail depending on the createMode argument.
380  *
381  * The file can be opened for reading, writing or both as specified in the accessMode argument. If
382  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE then a write lock will be placed
383  * on the file, otherwise a read lock will be placed on the file.
384  *
385  * If attempting to lock a file that already has an incompatible lock on it this function will block
386  * until the lock can be obtained. This function may block even if it creates the file because
387  * creating the file and locking it is not atomic.
388  *
389  * If there was an error NULL is returned and resultPtr is set to:
390  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
391  * - LE_FAULT if there was an error.
392  *
393  * @return
394  * Buffered file stream handle to the file if successful.
395  * NULL if there was an error.
396  */
397 //--------------------------------------------------------------------------------------------------
399 (
400  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
401  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
402  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
403  mode_t permissions, ///< [IN] File permissions used when creating the file.
404  /// See the function header comments for more details.
405  le_result_t* resultPtr ///< [OUT] Pointer to result code. This can be NULL if
406  /// the result code is not wanted.
407 );
408 
409 
410 //--------------------------------------------------------------------------------------------------
411 /**
412  * Locks an existing file and opens a C standard library buffered file stream to it.
413  *
414  * The file can be open for reading, writing or both read and write as specified in the accessMode
415  * argument. If accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE then a write lock
416  * will be placed on the file, otherwise a read lock will be placed on the file.
417  *
418  * If attempting to lock a file that already has an incompatible lock on it, this function will
419  * return NULL immediately and set resultPtr to LE_WOULD_BLOCK.
420  *
421  * If there was an error NULL is returned and resultPtr is set to:
422  * - LE_NOT_FOUND if the file does not exist.
423  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
424  * - LE_FAULT if there was an error.
425  *
426  * @return
427  * Buffered file stream handle to the file if successful.
428  * NULL if there was an error.
429  */
430 //--------------------------------------------------------------------------------------------------
432 (
433  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
434  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
435  le_result_t* resultPtr ///< [OUT] Pointer to result code.
436 );
437 
438 
439 //--------------------------------------------------------------------------------------------------
440 /**
441  * Creates a file, locks it and opens a C standard library buffered file stream to it.
442  *
443  * If the file does not exist, it will be created with the file permissions specified in the arugment
444  * permissions (modified by the process's umask). Refer to the POSIX function open(2) for details
445  * of mode_t:
446  *
447  * http://man7.org/linux/man-pages/man2/open.2.html
448  *
449  * If the file already exists, this function will either replace the existing file, open the
450  * existing file or fail depending on the createMode argument.
451  *
452  * The file can be opened for reading, writing or both as specified in the accessMode argument. If
453  * accessMode is either LE_FLOCK_WRITE or LE_FLOCK_READ_AND_WRITE then a write lock will be placed
454  * on the file, otherwise a read lock will be placed on the file.
455  *
456  * If attempting to lock a file that already has an incompatible lock on it, this function will
457  * return NULL immediately and set resultPtr to LE_WOULD_BLOCK. This function may fail with
458  * LE_WOULD_BLOCK even if it creates the file because creating the file and locking it is not
459  * atomic.
460  *
461  * If there was an error NULL is returned and resultPtr is set to:
462  * - LE_DUPLICATE if the file already exists and LE_FLOCK_FAIL_IF_EXIST is specified in createMode.
463  * - LE_WOULD_BLOCK if there is already an incompatible lock on the file.
464  * - LE_FAULT if there was an error.
465  *
466  * @return
467  * Buffered file stream handle to the file if successful.
468  * NULL if there was an error.
469  */
470 //--------------------------------------------------------------------------------------------------
472 (
473  const char* pathNamePtr, ///< [IN] Pointer to the path name of the file to open.
474  le_flock_AccessMode_t accessMode, ///< [IN] Access mode to open the file.
475  le_flock_CreateMode_t createMode, ///< [IN] Action to take if the file already exists.
476  mode_t permissions, ///< [IN] File permissions used when creating the file.
477  /// See the function header comments for more details.
478  le_result_t* resultPtr ///< [OUT] Pointer to result code.
479 );
480 
481 
482 //--------------------------------------------------------------------------------------------------
483 /**
484  * Closes the file stream and releases the lock.
485  */
486 //--------------------------------------------------------------------------------------------------
488 (
489  FILE* fileStreamPtr
490 );
491 
492 
493 #endif //LEGATO_FLOCK_INCLUDE_GUARD
int le_flock_TryCreate(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions)
Opens the file for reading.
Definition: le_fileLock.h:177
le_flock_CreateMode_t
Definition: le_fileLock.h:193
le_result_t
Definition: le_basics.h:35
Opens the file for reading and writing.
Definition: le_fileLock.h:181
Fails if the file already exists.
Definition: le_fileLock.h:197
int le_flock_Open(const char *pathNamePtr, le_flock_AccessMode_t accessMode)
void le_flock_Close(int fd)
FILE * le_flock_TryOpenStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_result_t *resultPtr)
Definition: le_fileLock.h:179
le_flock_AccessMode_t
Definition: le_fileLock.h:175
Opens the file for writing.
Definition: le_fileLock.h:178
Opens the file if it already exists.
Definition: le_fileLock.h:195
Replaces the file if it already exists.
Definition: le_fileLock.h:196
void le_flock_CloseStream(FILE *fileStreamPtr)
FILE * le_flock_CreateStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions, le_result_t *resultPtr)
Definition: le_fileLock.h:182
FILE * le_flock_OpenStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_result_t *resultPtr)
int le_flock_TryOpen(const char *pathNamePtr, le_flock_AccessMode_t accessMode)
int le_flock_Create(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions)
FILE * le_flock_TryCreateStream(const char *pathNamePtr, le_flock_AccessMode_t accessMode, le_flock_CreateMode_t createMode, mode_t permissions, le_result_t *resultPtr)