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