// fs.c -- filesystem access
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <uv.h>
#ifdef MSWIN
# include <shlobj.h>
#endif
#include "auto/config.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
#if defined(HAVE_ACL)
# ifdef HAVE_SYS_ACL_H
# include <sys/acl.h>
# endif
# ifdef HAVE_SYS_ACCESS_H
# include <sys/access.h>
# endif
#endif
#ifdef HAVE_XATTR
# include <sys/xattr.h>
#endif
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/errors.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/macros_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option_vars.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/vim_defs.h"
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef MSWIN
# include "nvim/mbyte.h"
# include "nvim/option.h"
# include "nvim/os/os_win_console.h"
# include "nvim/strings.h"
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fs.c.generated.h"
#endif
#ifdef HAVE_XATTR
static const char e_xattr_erange[]
= N_("E1506: Buffer too small to copy xattr value or key");
static const char e_xattr_e2big[]
= N_("E1508: Size of the extended attribute value is larger than the maximum size allowed");
static const char e_xattr_other[]
= N_("E1509: Error occurred when reading or writing extended attribute");
#endif
#define RUN_UV_FS_FUNC(ret, func, ...) \
do { \
uv_fs_t req; \
ret = func(NULL, &req, __VA_ARGS__); \
uv_fs_req_cleanup(&req); \
} while (0)
// Many fs functions from libuv return that value on success.
static const int kLibuvSuccess = 0;
/// Changes the current directory to `path`.
///
/// @return 0 on success, or negative error code.
int os_chdir(const char *path)
FUNC_ATTR_NONNULL_ALL
{
if (p_verbose >= 5) {
verbose_enter();
smsg(0, "chdir(%s)", path);
verbose_leave();
}
int err = uv_chdir(path);
if (err == 0) {
ui_call_chdir(cstr_as_string(path));
}
return err;
}
/// Get the name of current directory.
///
/// @param buf Buffer to store the directory name.
/// @param len Length of `buf`.
/// @return `OK` for success, `FAIL` for failure.
int os_dirname(char *buf, size_t len)
FUNC_ATTR_NONNULL_ALL
{
int error_number;
if ((error_number = uv_cwd(buf, &len)) != kLibuvSuccess) {
xstrlcpy(buf, uv_strerror(error_number), len);
return FAIL;
}
return OK;
}
/// Check if the given path is a directory and not a symlink to a directory.
/// @return `true` if `name` is a directory and NOT a symlink to a directory.
/// `false` if `name` is not a directory or if an error occurred.
bool os_isrealdir(const char *name)
FUNC_ATTR_NONNULL_ALL
{
uv_fs_t request;
if (uv_fs_lstat(NULL, &request, name, NULL) != kLibuvSuccess) {
return false;
}
if (S_ISLNK(
|