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