67 lines · cpp
1//===-- Linux implementation of getcwd ------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/unistd/getcwd.h"10 11#include "src/__support/OSUtil/syscall.h" // For internal syscall function.12#include "src/__support/common.h"13#include "src/__support/macros/config.h"14#include "src/string/allocating_string_utils.h" // For strdup.15 16#include "src/__support/libc_errno.h"17#include <linux/limits.h> // This is safe to include without any name pollution.18#include <sys/syscall.h> // For syscall numbers.19 20namespace LIBC_NAMESPACE_DECL {21 22namespace {23 24bool getcwd_syscall(char *buf, size_t size) {25 int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_getcwd, buf, size);26 if (ret < 0) {27 libc_errno = -ret;28 return false;29 } else if (ret == 0 || buf[0] != '/') {30 libc_errno = ENOENT;31 return false;32 }33 return true;34}35 36} // anonymous namespace37 38LLVM_LIBC_FUNCTION(char *, getcwd, (char *buf, size_t size)) {39 if (buf == nullptr) {40 // We match glibc's behavior here and return the cwd in a malloc-ed buffer.41 // We will allocate a static buffer of size PATH_MAX first and fetch the cwd42 // into it. This way, if the syscall fails, we avoid unnecessary malloc43 // and free.44 char pathbuf[PATH_MAX];45 if (!getcwd_syscall(pathbuf, PATH_MAX))46 return nullptr;47 auto cwd = internal::strdup(pathbuf);48 if (!cwd) {49 libc_errno = ENOMEM;50 return nullptr;51 }52 return *cwd;53 } else if (size == 0) {54 libc_errno = EINVAL;55 return nullptr;56 }57 58 // TODO: When buf is not sufficient, evaluate the full cwd path using59 // alternate approaches.60 61 if (!getcwd_syscall(buf, size))62 return nullptr;63 return buf;64}65 66} // namespace LIBC_NAMESPACE_DECL67