• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Implementation of fcntl -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/fcntl/fcntl.h"
10 
11 #include "hdr/fcntl_macros.h"
12 #include "hdr/types/struct_f_owner_ex.h"
13 #include "hdr/types/struct_flock.h"
14 #include "hdr/types/struct_flock64.h"
15 #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
16 #include "src/__support/common.h"
17 #include "src/errno/libc_errno.h"
18 
19 #include <stdarg.h>
20 #include <sys/syscall.h> // For syscall numbers.
21 
22 // The OFD file locks require special handling for LARGEFILES
23 namespace LIBC_NAMESPACE {
24 LLVM_LIBC_FUNCTION(int, fcntl, (int fd, int cmd, ...)) {
25   void *arg;
26   va_list varargs;
27   va_start(varargs, cmd);
28   arg = va_arg(varargs, void *);
29   va_end(varargs);
30 
31   switch (cmd) {
32   case F_SETLKW:
33     return syscall_impl<int>(SYS_fcntl, fd, cmd, arg);
34   case F_OFD_SETLKW: {
35     struct flock *flk = reinterpret_cast<struct flock *>(arg);
36     // convert the struct to a flock64
37     struct flock64 flk64;
38     flk64.l_type = flk->l_type;
39     flk64.l_whence = flk->l_whence;
40     flk64.l_start = flk->l_start;
41     flk64.l_len = flk->l_len;
42     flk64.l_pid = flk->l_pid;
43     // create a syscall
44     return syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
45   }
46   case F_OFD_GETLK:
47   case F_OFD_SETLK: {
48     struct flock *flk = reinterpret_cast<struct flock *>(arg);
49     // convert the struct to a flock64
50     struct flock64 flk64;
51     flk64.l_type = flk->l_type;
52     flk64.l_whence = flk->l_whence;
53     flk64.l_start = flk->l_start;
54     flk64.l_len = flk->l_len;
55     flk64.l_pid = flk->l_pid;
56     // create a syscall
57     int retVal = syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
58     // On failure, return
59     if (retVal == -1)
60       return -1;
61     // Check for overflow, i.e. the offsets are not the same when cast
62     // to off_t from off64_t.
63     if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
64         static_cast<off_t>(flk64.l_start) != flk64.l_start) {
65       libc_errno = EOVERFLOW;
66       return -1;
67     }
68     // Now copy back into flk, in case flk64 got modified
69     flk->l_type = flk64.l_type;
70     flk->l_whence = flk64.l_whence;
71     flk->l_start = flk64.l_start;
72     flk->l_len = flk64.l_len;
73     flk->l_pid = flk64.l_pid;
74     return retVal;
75   }
76   case F_GETOWN: {
77     struct f_owner_ex fex;
78     int retVal = syscall_impl<int>(SYS_fcntl, fd, F_GETOWN_EX, &fex);
79     if (retVal == -EINVAL)
80       return syscall_impl<int>(SYS_fcntl, fd, cmd,
81                                reinterpret_cast<void *>(arg));
82     if (static_cast<unsigned long>(retVal) <= -4096UL)
83       return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid;
84 
85     libc_errno = -retVal;
86     return -1;
87   }
88   // The general case
89   default:
90     return syscall_impl<int>(SYS_fcntl, fd, cmd, reinterpret_cast<void *>(arg));
91   }
92 }
93 } // namespace LIBC_NAMESPACE
94