aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2019-07-23 20:56:27 +0200
committerJustin M. Keyes <justinkz@gmail.com>2019-07-25 22:32:23 +0200
commitbb3a0099c6909edc779cf9d2eff9656dab9a967e (patch)
tree8fdf027c2d30c17c20d5d521bf18e116912d831d /src
parent8a9c9a996322a1d111c55efb156710add68da358 (diff)
downloadrneovim-bb3a0099c6909edc779cf9d2eff9656dab9a967e.tar.gz
rneovim-bb3a0099c6909edc779cf9d2eff9656dab9a967e.tar.bz2
rneovim-bb3a0099c6909edc779cf9d2eff9656dab9a967e.zip
os/fs: introduce os_fopen()
Windows: Using fopen() directly may need UTF-16 filepath conversion. To achieve that, os_fopen() goes through os_open(). fix #10586
Diffstat (limited to 'src')
-rw-r--r--src/nvim/macros.h2
-rw-r--r--src/nvim/os/fs.c73
2 files changed, 69 insertions, 6 deletions
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 61009528a8..5e1ccbc5e8 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -86,7 +86,7 @@
#define READBIN "rb"
#define APPENDBIN "ab"
-# define mch_fopen(n, p) fopen((n), (p))
+# define mch_fopen(n, p) os_fopen((n), (p))
/* mch_open_rw(): invoke os_open() with third argument for user R/W. */
#if defined(UNIX) /* open in rw------- mode */
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 0ded36942e..dcb3ef7c4a 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -404,10 +404,11 @@ end:
/// calls (read, write, lseek, fcntl, etc.). If the operation fails, a libuv
/// error code is returned, and no file is created or modified.
///
+/// @param path Filename
/// @param flags Bitwise OR of flags defined in <fcntl.h>
/// @param mode Permissions for the newly-created file (IGNORED if 'flags' is
/// not `O_CREAT` or `O_TMPFILE`), subject to the current umask
-/// @return file descriptor, or libuv error code on failure
+/// @return file descriptor, or negative error code on failure
int os_open(const char *path, int flags, int mode)
{
if (path == NULL) { // uv_fs_open asserts on NULL. #7561
@@ -418,6 +419,68 @@ int os_open(const char *path, int flags, int mode)
return r;
}
+/// Compatibility wrapper conforming to fopen(3).
+///
+/// Windows: works with UTF-16 filepaths by delegating to libuv (os_open).
+///
+/// Future: remove this, migrate callers to os/fileio.c ?
+/// But file_open_fd does not support O_RDWR yet.
+///
+/// @param path Filename
+/// @param flags String flags, one of { r w a r+ w+ a+ rb wb ab }
+/// @return FILE pointer, or NULL on error.
+FILE *os_fopen(const char *path, const char *flags)
+{
+ assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2);
+ int iflags = 0;
+ // Per table in fopen(3) manpage.
+ if (flags[1] == '\0' || flags[1] == 'b') {
+ switch (flags[0]) {
+ case 'r':
+ iflags = O_RDONLY;
+ break;
+ case 'w':
+ iflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ iflags = O_WRONLY | O_CREAT | O_APPEND;
+ break;
+ default:
+ abort();
+ }
+#ifdef WIN32
+ if (flags[1] == 'b') {
+ iflags |= O_BINARY;
+ }
+#endif
+ } else {
+ // char 0 must be one of ('r','w','a').
+ // char 1 is always '+' ('b' is handled above).
+ assert(flags[1] == '+');
+ switch (flags[0]) {
+ case 'r':
+ iflags = O_RDWR;
+ break;
+ case 'w':
+ iflags = O_RDWR | O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ iflags = O_RDWR | O_CREAT | O_APPEND;
+ break;
+ default:
+ abort();
+ }
+ }
+ // Per open(2) manpage.
+ assert((iflags|O_RDONLY) || (iflags|O_WRONLY) || (iflags|O_RDWR));
+ // Per fopen(3) manpage: default to 0666, it will be umask-adjusted.
+ int fd = os_open(path, iflags, 0666);
+ if (fd < 0) {
+ return NULL;
+ }
+ return fdopen(fd, flags);
+}
+
/// Sets file descriptor `fd` to close-on-exec.
//
// @return -1 if failed to set, 0 otherwise.
@@ -829,12 +892,12 @@ int os_mkdir_recurse(const char *const dir, int32_t mode,
// We're done when it's "/" or "c:/".
const size_t dirlen = strlen(dir);
char *const curdir = xmemdupz(dir, dirlen);
- char *const past_head = (char *) get_past_head((char_u *) curdir);
+ char *const past_head = (char *)get_past_head((char_u *)curdir);
char *e = curdir + dirlen;
const char *const real_end = e;
const char past_head_save = *past_head;
- while (!os_isdir((char_u *) curdir)) {
- e = (char *) path_tail_with_sep((char_u *) curdir);
+ while (!os_isdir((char_u *)curdir)) {
+ e = (char *)path_tail_with_sep((char_u *)curdir);
if (e <= past_head) {
*past_head = NUL;
break;
@@ -986,7 +1049,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
///
/// @return `true` if the two FileInfos represent the same file.
bool os_fileinfo_id_equal(const FileInfo *file_info_1,
- const FileInfo *file_info_2)
+ const FileInfo *file_info_2)
FUNC_ATTR_NONNULL_ALL
{
return file_info_1->stat.st_ino == file_info_2->stat.st_ino