1 /* 2 * Copyright 2007, Vasilis Kaoutsis, kaoutsis@sch.gr. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 10 #include <errno_private.h> 11 12 13 int 14 lockf(int fileDescriptor, int function, off_t size) 15 { 16 struct flock fileLock; 17 fileLock.l_start = 0; 18 fileLock.l_len = size; 19 fileLock.l_whence = SEEK_CUR; 20 21 if (function == F_ULOCK) { 22 // unlock locked sections 23 fileLock.l_type = F_UNLCK; 24 return fcntl(fileDescriptor, F_SETLK, &fileLock); 25 } else if (function == F_LOCK) { 26 // lock a section for exclusive use 27 fileLock.l_type = F_WRLCK; 28 return fcntl(fileDescriptor, F_SETLKW, &fileLock); 29 } else if (function == F_TLOCK) { 30 // test and lock a section for exclusive use 31 fileLock.l_type = F_WRLCK; 32 return fcntl(fileDescriptor, F_SETLK, &fileLock); 33 } else if (function == F_TEST) { 34 // test a section for locks by other processes 35 fileLock.l_type = F_WRLCK; 36 if (fcntl(fileDescriptor, F_GETLK, &fileLock) == -1) 37 return -1; 38 if (fileLock.l_type == F_UNLCK) 39 return 0; 40 41 __set_errno(EAGAIN); 42 return -1; 43 } else { 44 __set_errno(EINVAL); 45 return -1; 46 } 47 48 // Notes regarding standard compliance (cf. Open Group Base Specs): 49 // * "The interaction between fcntl() and lockf() locks is unspecified." 50 // * fcntl() locking works on a per-process level. The lockf() description 51 // is a little fuzzy on whether it works the same way. The first quote 52 // seem to describe per-thread locks (though it might actually mean 53 // "threads of other processes"), but the others quotes are strongly 54 // indicating per-process locks: 55 // - "Calls to lockf() from other threads which attempt to lock the locked 56 // file section shall either return an error value or block until the 57 // section becomes unlocked." 58 // - "All the locks for a process are removed when the process 59 // terminates." 60 // - "F_TEST shall detect if a lock by another process is present on the 61 // specified section." 62 // - "The sections locked with F_LOCK or F_TLOCK may, in whole or in part, 63 // contain or be contained by a previously locked section for the same 64 // process. When this occurs, or if adjacent locked sections would 65 // occur, the sections shall be combined into a single locked section." 66 // * fcntl() and lockf() handle a 0 size argument differently. The former 67 // use the file size at the time of the call: 68 // "If the command is F_SETLKW and the process must wait for another 69 // process to release a lock, then the range of bytes to be locked shall 70 // be determined before the fcntl() function blocks. If the file size 71 // or file descriptor seek offset change while fcntl() is blocked, this 72 // shall not affect the range of bytes locked." 73 // lockf(), on the other hand, is supposed to create a lock whose size 74 // dynamically adjusts to the file size: 75 // "If size is 0, the section from the current offset through the largest 76 // possible file offset shall be locked (that is, from the current 77 // offset through the present or any future end-of-file)." 78 // * The lock release handling when closing descriptors sounds a little 79 // different, though might actually mean the same. 80 // For fcntl(): 81 // "All locks associated with a file for a given process shall be removed 82 // when a file descriptor for that file is closed by that process or the 83 // process holding that file descriptor terminates." 84 // For lockf(): 85 // "File locks shall be released on first close by the locking process of 86 // any file descriptor for the file." 87 } 88