mirror of
https://github.com/neovim/neovim.git
synced 2025-10-07 18:36:30 +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 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 */
|
||||
|
@@ -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.
|
||||
|
@@ -22,6 +22,7 @@ describe('fileio', function()
|
||||
os.remove('Xtest_startup_file1')
|
||||
os.remove('Xtest_startup_file1~')
|
||||
os.remove('Xtest_startup_file2')
|
||||
os.remove('Xtest_тест.md')
|
||||
rmdir('Xtest_startup_swapdir')
|
||||
end)
|
||||
|
||||
@@ -85,7 +86,22 @@ describe('fileio', function()
|
||||
|
||||
eq('foobar', foobar_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)
|
||||
|
||||
|
Reference in New Issue
Block a user