[libc-commits] [libc] [libc] Implement fcntl() function (PR #89507)

Vinayak Dev via libc-commits libc-commits at lists.llvm.org
Fri Apr 26 15:59:51 PDT 2024


================
@@ -0,0 +1,107 @@
+//===-- Implementation of fcntl -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/fcntl/fcntl.h"
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/types/struct_flock.h"
+#include "hdr/types/struct_flock64.h"
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/errno/libc_errno.h"
+
+#include <stdarg.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+// To avoid conflict with system headers when building
+// in overlay mode.
+namespace helper {
+enum pid_type {
+  F_OWNER_TID = 0,
+  F_OWNER_PID,
+  F_OWNER_PGRP,
+};
+struct fowner_ex {
+  enum pid_type type;
+  pid_t pid;
+};
+} // namespace helper
+
+// The OFD file locks require special handling for LARGEFILES
+namespace LIBC_NAMESPACE {
+LLVM_LIBC_FUNCTION(int, fcntl, (int fd, int cmd, ...)) {
+  void *arg;
+  va_list varargs;
+  va_start(varargs, cmd);
+  arg = va_arg(varargs, void *);
+  va_end(varargs);
+
+  switch (cmd) {
+  case F_SETLKW:
+    return syscall_impl<int>(SYS_fcntl, fd, cmd, arg);
+  case F_OFD_SETLKW: {
+    struct flock *flk = reinterpret_cast<struct flock *>(arg);
+    // convert the struct to a flock64
+    struct flock64 flk64;
+    flk64.l_type = flk->l_type;
+    flk64.l_whence = flk->l_whence;
+    flk64.l_start = flk->l_start;
+    flk64.l_len = flk->l_len;
+    flk64.l_pid = flk->l_pid;
+    // create a syscall
+    return syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
+  }
+  case F_OFD_GETLK:
+  case F_OFD_SETLK: {
+    struct flock *flk = reinterpret_cast<struct flock *>(arg);
+    // convert the struct to a flock64
+    struct flock64 flk64;
+    flk64.l_type = flk->l_type;
+    flk64.l_whence = flk->l_whence;
+    flk64.l_start = flk->l_start;
+    flk64.l_len = flk->l_len;
+    flk64.l_pid = flk->l_pid;
+    // create a syscall
+    int retVal = syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
+    // On failure, return
+    if (retVal == -1)
+      return -1;
+    // Check for overflow, i.e. the offsets are not the same when cast
+    // to off_t from off64_t.
+    if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
+        static_cast<off_t>(flk64.l_start) != flk64.l_start) {
+      libc_errno = EOVERFLOW;
+      return -1;
+    }
+    // Now copy back into flk, in case flk64 got modified
+    flk->l_type = flk64.l_type;
+    flk->l_whence = flk64.l_whence;
+    flk->l_start = flk64.l_start;
+    flk->l_len = flk64.l_len;
+    flk->l_pid = flk64.l_pid;
+    return retVal;
+  }
+    // The general case
+  default: {
+    if (cmd == F_GETOWN) {
+      struct helper::fowner_ex fex;
+      int retVal = syscall_impl<int>(SYS_fcntl, fd, F_GETOWN_EX, &fex);
+      if (retVal == -EINVAL)
+        return syscall_impl<int>(SYS_fcntl, fd, cmd,
+                                 reinterpret_cast<void *>(arg));
+      if (static_cast<uint64_t>(retVal) <= -4096UL)
----------------
vinayakdsci wrote:

I am sorry, this should have cast to uint32_t. This check allows a general check against syscall errors, and also because MAX_ERRNO is defined to be 4095 in the kernel. Checking against -4096UL means that if the value is strictly larger than this, than it is certain that the result is malformed. Note that -4096UL would mean 2^32 - 4096, by using two's complement here, which would have not been preserved in an int.

https://github.com/llvm/llvm-project/pull/89507


More information about the libc-commits mailing list