xref: /haiku/src/system/libroot/posix/unistd/lockf.cpp (revision cb93a65449a8fe1b02b6fc4a44e2e109ee4652a8)
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