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