mirror of
https://github.com/neovim/neovim.git
synced 2025-10-07 10:26:31 +00:00
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
This commit is contained in:
@@ -86,7 +86,7 @@
|
|||||||
#define READBIN "rb"
|
#define READBIN "rb"
|
||||||
#define APPENDBIN "ab"
|
#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. */
|
/* mch_open_rw(): invoke os_open() with third argument for user R/W. */
|
||||||
#if defined(UNIX) /* open in rw------- mode */
|
#if defined(UNIX) /* open in rw------- mode */
|
||||||
|
@@ -404,10 +404,11 @@ end:
|
|||||||
/// calls (read, write, lseek, fcntl, etc.). If the operation fails, a libuv
|
/// calls (read, write, lseek, fcntl, etc.). If the operation fails, a libuv
|
||||||
/// error code is returned, and no file is created or modified.
|
/// 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 flags Bitwise OR of flags defined in <fcntl.h>
|
||||||
/// @param mode Permissions for the newly-created file (IGNORED if 'flags' is
|
/// @param mode Permissions for the newly-created file (IGNORED if 'flags' is
|
||||||
/// not `O_CREAT` or `O_TMPFILE`), subject to the current umask
|
/// 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)
|
int os_open(const char *path, int flags, int mode)
|
||||||
{
|
{
|
||||||
if (path == NULL) { // uv_fs_open asserts on NULL. #7561
|
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;
|
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.
|
/// Sets file descriptor `fd` to close-on-exec.
|
||||||
//
|
//
|
||||||
// @return -1 if failed to set, 0 otherwise.
|
// @return -1 if failed to set, 0 otherwise.
|
||||||
|
@@ -22,6 +22,7 @@ describe('fileio', function()
|
|||||||
os.remove('Xtest_startup_file1')
|
os.remove('Xtest_startup_file1')
|
||||||
os.remove('Xtest_startup_file1~')
|
os.remove('Xtest_startup_file1~')
|
||||||
os.remove('Xtest_startup_file2')
|
os.remove('Xtest_startup_file2')
|
||||||
|
os.remove('Xtest_тест.md')
|
||||||
rmdir('Xtest_startup_swapdir')
|
rmdir('Xtest_startup_swapdir')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -85,7 +86,22 @@ describe('fileio', function()
|
|||||||
|
|
||||||
eq('foobar', foobar_contents);
|
eq('foobar', foobar_contents);
|
||||||
eq('foo', bar_contents);
|
eq('foo', bar_contents);
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('readfile() on multibyte filename #10586', function()
|
||||||
|
clear()
|
||||||
|
local text = {
|
||||||
|
'line1',
|
||||||
|
' ...line2... ',
|
||||||
|
'',
|
||||||
|
'line3!',
|
||||||
|
'тест yay тест.',
|
||||||
|
'',
|
||||||
|
}
|
||||||
|
local fname = 'Xtest_тест.md'
|
||||||
|
funcs.writefile(text, fname, 's')
|
||||||
|
table.insert(text, '')
|
||||||
|
eq(text, funcs.readfile(fname, 'b'))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user