diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2019-07-23 20:56:27 +0200 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2019-07-25 22:32:23 +0200 |
commit | bb3a0099c6909edc779cf9d2eff9656dab9a967e (patch) | |
tree | 8fdf027c2d30c17c20d5d521bf18e116912d831d /src | |
parent | 8a9c9a996322a1d111c55efb156710add68da358 (diff) | |
download | rneovim-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.h | 2 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 73 |
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 |